# 스티비 API - **원본 OpenAPI Version:** `3.0.3` - **API Version:** `2.0.0` - **Terms of service:**  - **Contact:** ### 소개 이 문서는 스티비 API의 인증 방식, 공통 요청 규칙, 오류 응답 형식과 각 API의 요청 및 응답 구조를 설명합니다. ### AI로 API 연동하기 AI 코딩 도구에 [LLM용 문서 목차](https://developers.stibee.com/llms.txt) 주소를 전달하면 필요한 API별 문서를 참고할 수 있습니다. 전체 명세는 [llms-full.txt](https://developers.stibee.com/llms-full.txt)에서 제공합니다. 사용 예시: > 를 읽고, 스티비 주소록에 구독자를 추가하는 코드를 작성해줘. ### 요금제별 권한 | API | 스탠다드 | 프로 | 엔터프라이즈 | | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | -- | ------ | | [구독자](https://developers.stibee.com/%EC%8A%A4%ED%8B%B0%EB%B9%84-api/tag/%EC%A3%BC%EC%86%8C%EB%A1%9D-%EA%B5%AC%EB%8F%85%EC%9E%90) | ✅ | ✅ | ✅ | | [이메일](https://developers.stibee.com/%EC%8A%A4%ED%8B%B0%EB%B9%84-api/tag/%EC%9D%B4%EB%A9%94%EC%9D%BC), [그룹](https://developers.stibee.com/%EC%8A%A4%ED%8B%B0%EB%B9%84-api/tag/%EC%A3%BC%EC%86%8C%EB%A1%9D-%EA%B7%B8%EB%A3%B9) | - | ✅ | ✅ | | [주소록](https://developers.stibee.com/%EC%8A%A4%ED%8B%B0%EB%B9%84-api/tag/%EC%A3%BC%EC%86%8C%EB%A1%9D), [발신자 주소](https://developers.stibee.com/%EC%8A%A4%ED%8B%B0%EB%B9%84-api/tag/%EC%A3%BC%EC%86%8C%EB%A1%9D-%EB%B0%9C%EC%8B%A0%EC%9E%90-%EC%9D%B4%EB%A9%94%EC%9D%BC-%EC%A3%BC%EC%86%8C) | - | - | ✅ | - [구독자](https://developers.stibee.com/%EC%8A%A4%ED%8B%B0%EB%B9%84-api/tag/%EC%A3%BC%EC%86%8C%EB%A1%9D-%EA%B5%AC%EB%8F%85%EC%9E%90): 구독자 추가, 수정 등 구독자 관리를 자동화해 고객 DB와 연동할 수 있습니다. - [이메일](https://developers.stibee.com/%EC%8A%A4%ED%8B%B0%EB%B9%84-api/tag/%EC%9D%B4%EB%A9%94%EC%9D%BC), [그룹](https://developers.stibee.com/%EC%8A%A4%ED%8B%B0%EB%B9%84-api/tag/%EC%A3%BC%EC%86%8C%EB%A1%9D-%EA%B7%B8%EB%A3%B9): 이메일 생성, 편집, 발송, 그룹 관리를 자동화할 수 있습니다. - [주소록](https://developers.stibee.com/%EC%8A%A4%ED%8B%B0%EB%B9%84-api/tag/%EC%A3%BC%EC%86%8C%EB%A1%9D), [발신자 주소](https://developers.stibee.com/%EC%8A%A4%ED%8B%B0%EB%B9%84-api/tag/%EC%A3%BC%EC%86%8C%EB%A1%9D-%EB%B0%9C%EC%8B%A0%EC%9E%90-%EC%9D%B4%EB%A9%94%EC%9D%BC-%EC%A3%BC%EC%86%8C): 주소록 관리와 발신자 이메일 주소 관리를 자동화할 수 있습니다. ### 요청 속도 제한 | API | 요청 속도 제한 | | ---------- | ---------- | | 구독자 대량 추가 | 최대 10회/분 | | 구독자 목록 조회 | 최대 100회/분 | | 구독자 성과 조회 | 최대 100회/분 | | 이메일 성과 조회 | 최대 100회/분 | | 그 외 모든 API | 최대 1000회/분 | 제한은 1분 단위로 집계되며, 초과하면 HTTP 429와 함께 `Errors.Authorization.TooManyRequest`가 반환됩니다. 요금제별 권한, 요청 속도 제한은 각 API 항목별 페이지의 제목 위에 표시되어있습니다. ### Base URL 모든 API 요청은 다음 Base URL을 기준으로 합니다: `https://api.stibee.com/v2` 이메일 목록 조회 예시 ```http GET https://api.stibee.com/v2/emails ``` ### 인증 모든 API 요청에는 인증을 위해 `AccessToken` 헤더가 필요합니다. `AccessToken`은 스티비 서비스의 \[워크스페이스 설정 > API 키]에서 생성할 수 있습니다. 자세한 내용은 [스티비 도움말 > 주소록 API 사용하기 > API 키 만들기](https://help.stibee.com/api-webhook/api#id-1-api-2)를 참고하세요. 2025년 1월 21일 이후에 생성된 API 키로만 인증할 수 있습니다. `AccessToken` 헤더가 없거나 유효하지 않으면 `Errors.Authorization.NoToken` (message: "존재하지 않는 토큰 입니다.") 오류가 반환됩니다. #### 인증 확인 `/auth-check`는 발급된 API 키를 사용해 인증이 정상적으로 되는지 확인할 수 있는 테스트용 요청입니다. ```http GET /auth-check AccessToken: YOUR_API_KEY ``` ### 오류 응답 요청이 성공하면 `200 OK`가 반환됩니다. 요청 값이 잘못되었거나 처리할 수 없는 경우 `400 Bad Request`가, 요청한 리소스를 찾을 수 없는 경우 `404 Not Found`가 반환됩니다. 요청 속도 제한을 초과한 경우에는 `429 Too Many Requests`와 함께 `Errors.Authorization.TooManyRequest`가 반환됩니다. 오류 응답 형식은 다음과 같습니다. ```JSON { "code":"Errors.Data.InvalidRequest", "httpStatusCode":400, "message":"잘못된 요청입니다." } ``` 분기 처리에는 `code`를 사용하세요. `message`는 사람이 읽기 위한 값이며 사전 고지 없이 바뀔 수 있습니다. 오류에 따라 `values`가 함께 반환됩니다. `values.message`는 무엇이 잘못되었는지 구체적으로 알려줍니다. ```JSON { "code":"Errors.Data.LimitExceeded", "httpStatusCode":400, "message":"요청 제한을 초과하였습니다.", "values":{"message":"이메일 목록 조회는 한 번에 최대 100건까지입니다."} } ``` `message`에 `{중괄호}`가 있으면 서버가 치환하지 않고 그대로 보냅니다. 치환할 값은 `values`의 같은 이름 키에 담겨 옵니다. ```JSON { "code":"Errors.List.TooManyGroups", "httpStatusCode":400, "message":"그룹은 최대 {maxCount}개 까지만 만들 수 있습니다.", "values":{"maxCount":30} } ``` 일시적인 오류로 `Errors.Service.TemporaryError` 코드가 `400`과 함께 반환될 수 있습니다. 이 코드를 받으면 재시도 처리를 권장합니다. `5XX` 응답도 일시적인 시스템 오류일 수 있습니다. 이 경우에도 재시도 처리를 권장합니다. `5XX`는 위 오류 응답 형식을 따르지 않을 수 있습니다. ### 요청 형식 쿼리스트링을 제외한 모든 요청 본문은 `application/json` 형식이며, 인코딩은 `UTF-8`입니다. ## Contents **Operations** - [GET /emails](#scalar-operation-get-emails) - [POST /emails](#scalar-operation-post-emails) - [DELETE /emails/{id}](#scalar-operation-delete-emailsid) - [GET /emails/{id}](#scalar-operation-get-emailsid) - [PUT /emails/{id}](#scalar-operation-put-emailsid) - [POST /emails/{id}/cancel-reserve](#scalar-operation-post-emailsidcancel-reserve) - [POST /emails/{id}/copy](#scalar-operation-post-emailsidcopy) - [GET /emails/{id}/logs](#scalar-operation-get-emailsidlogs) - [POST /emails/{id}/reserve](#scalar-operation-post-emailsidreserve) - [POST /emails/{id}/send](#scalar-operation-post-emailsidsend) - [GET /emails/stats](#scalar-operation-get-emailsstats) - [GET /emails/{id}/content](#scalar-operation-get-emailsidcontent) - [POST /emails/{id}/content](#scalar-operation-post-emailsidcontent) - [POST /emails/{id}/tags/assign](#scalar-operation-post-emailsidtagsassign) - [POST /emails/{id}/tags/release](#scalar-operation-post-emailsidtagsrelease) - [GET /lists](#scalar-operation-get-lists) - [POST /lists](#scalar-operation-post-lists) - [DELETE /lists/{id}](#scalar-operation-delete-listsid) - [GET /lists/{id}](#scalar-operation-get-listsid) - [PUT /lists/{id}](#scalar-operation-put-listsid) - [POST /lists/{id}/copy](#scalar-operation-post-listsidcopy) - [POST /lists/{id}/groups/{groupId}/assign](#scalar-operation-post-listsidgroupsgroupidassign) - [POST /lists/{id}/groups/{groupId}/release](#scalar-operation-post-listsidgroupsgroupidrelease) - [DELETE /lists/{id}/subscribers](#scalar-operation-delete-listsidsubscribers) - [GET /lists/{id}/subscribers](#scalar-operation-get-listsidsubscribers) - [POST /lists/{id}/subscribers](#scalar-operation-post-listsidsubscribers) - [PUT /lists/{id}/subscribers/{subscriber}](#scalar-operation-put-listsidsubscriberssubscriber) - [POST /lists/{id}/subscribers/{subscriber}/unsubscribe](#scalar-operation-post-listsidsubscriberssubscriberunsubscribe) - [POST /lists/{id}/subscribers/batch](#scalar-operation-post-listsidsubscribersbatch) - [GET /lists/{id}/subscribers/count](#scalar-operation-get-listsidsubscriberscount) - [POST /lists/{id}/subscribers/double-optin](#scalar-operation-post-listsidsubscribersdouble-optin) - [POST /lists/{id}/subscribers/stats/query](#scalar-operation-post-listsidsubscribersstatsquery) - [GET /lists/{id}/groups](#scalar-operation-get-listsidgroups) - [POST /lists/{id}/groups](#scalar-operation-post-listsidgroups) - [DELETE /lists/{id}/groups/{groupId}](#scalar-operation-delete-listsidgroupsgroupid) - [PUT /lists/{id}/groups/{groupId}](#scalar-operation-put-listsidgroupsgroupid) - [GET /lists/{id}/senders](#scalar-operation-get-listsidsenders) - [POST /lists/{id}/senders](#scalar-operation-post-listsidsenders) - [DELETE /lists/{id}/senders/{email}](#scalar-operation-delete-listsidsendersemail) - [POST /lists/{id}/senders/{email}/verify](#scalar-operation-post-listsidsendersemailverify) **Schemas** - [CreateListRequest](#scalar-schema-createlistrequest) - [CreateListResponse](#scalar-schema-createlistresponse) - [CopyListResponse](#scalar-schema-copylistresponse) - [GetListsResponse](#scalar-schema-getlistsresponse) - [GetListsResponseItem](#scalar-schema-getlistsresponseitem) - [GetEmailsResponse](#scalar-schema-getemailsresponse) - [GetEmailResponse](#scalar-schema-getemailresponse) - [GetSubscribersVarsResponse](#scalar-schema-getsubscribersvarsresponse) - [GetSubscriberVarsResponse](#scalar-schema-getsubscribervarsresponse) - [CreateSubscriberVarRequest](#scalar-schema-createsubscribervarrequest) - [CreatedCopiedEmailResponse](#scalar-schema-createdcopiedemailresponse) - [AddSenderRequest](#scalar-schema-addsenderrequest) - [AddSenderResponse](#scalar-schema-addsenderresponse) - [Subscriber](#scalar-schema-subscriber) - [BatchSubscriberRequest](#scalar-schema-batchsubscriberrequest) - [BatchSubscriberResponse](#scalar-schema-batchsubscriberresponse) - [UpdateEmailRequest](#scalar-schema-updateemailrequest) - [EmailLogsResponse](#scalar-schema-emaillogsresponse) - [EmailLogItem](#scalar-schema-emaillogitem) - [GetEmailStatsResponse](#scalar-schema-getemailstatsresponse) - [EmailStats](#scalar-schema-emailstats) - [QuerySubscriberStatsRequest](#scalar-schema-querysubscriberstatsrequest) - [GetSubscriberStatsResponse](#scalar-schema-getsubscriberstatsresponse) - [CreateEmailRequest](#scalar-schema-createemailrequest) - [CreateEmailResponse](#scalar-schema-createemailresponse) - [AddSubscriberRequest](#scalar-schema-addsubscriberrequest) - [GetListResponse](#scalar-schema-getlistresponse) - [UpdateListRequest](#scalar-schema-updatelistrequest) - [SendDoubleOptinRequest](#scalar-schema-senddoubleoptinrequest) - [GetSubscribersResponse](#scalar-schema-getsubscribersresponse) - [GetSubscriberCountResponse](#scalar-schema-getsubscribercountresponse) - [UpdateSubscriberRequest](#scalar-schema-updatesubscriberrequest) - [AssignGroupRequest](#scalar-schema-assigngrouprequest) - [ReleaseGroupRequest](#scalar-schema-releasegrouprequest) - [DeleteSubscribersRequest](#scalar-schema-deletesubscribersrequest) - [GetListSenderResponse](#scalar-schema-getlistsenderresponse) - [CreateGroupRequest](#scalar-schema-creategrouprequest) - [CreateGroupResponse](#scalar-schema-creategroupresponse) - [GetGroupResponse](#scalar-schema-getgroupresponse) - [UpdateGroupRequest](#scalar-schema-updategrouprequest) - [GetEmailsErrorResponse](#scalar-schema-getemailserrorresponse) - [CreateEmailErrorResponse](#scalar-schema-createemailerrorresponse) - [UpdateEmailErrorResponse](#scalar-schema-updateemailerrorresponse) - [GetEmailLogsErrorResponse](#scalar-schema-getemaillogserrorresponse) - [GetEmailContentErrorResponse](#scalar-schema-getemailcontenterrorresponse) - [UpdateEmailContentErrorResponse](#scalar-schema-updateemailcontenterrorresponse) - [SendEmailErrorResponse](#scalar-schema-sendemailerrorresponse) - [ReserveEmailErrorResponse](#scalar-schema-reserveemailerrorresponse) - [CreateListErrorResponse](#scalar-schema-createlisterrorresponse) - [CopyListErrorResponse](#scalar-schema-copylisterrorresponse) - [GetListNotFoundResponse](#scalar-schema-getlistnotfoundresponse) - [AddListSenderErrorResponse](#scalar-schema-addlistsendererrorresponse) - [VerifyListSenderErrorResponse](#scalar-schema-verifylistsendererrorresponse) - [AddSubscriberErrorResponse](#scalar-schema-addsubscribererrorresponse) - [GetSubscribersErrorResponse](#scalar-schema-getsubscriberserrorresponse) - [DeleteSubscribersErrorResponse](#scalar-schema-deletesubscriberserrorresponse) - [SendDoubleOptinErrorResponse](#scalar-schema-senddoubleoptinerrorresponse) - [BatchAddSubscribersErrorResponse](#scalar-schema-batchaddsubscriberserrorresponse) - [AssignGroupErrorResponse](#scalar-schema-assigngrouperrorresponse) - [CreateGroupErrorResponse](#scalar-schema-creategrouperrorresponse) - [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) - [SharedErrorResponse_d07945da9c](#scalar-schema-sharederrorresponse-d07945da9c) - [SharedErrorResponse_6427954453](#scalar-schema-sharederrorresponse-6427954453) - [SharedErrorResponse_d9bfb03eb3](#scalar-schema-sharederrorresponse-d9bfb03eb3) - [SharedErrorResponse_b33e216723](#scalar-schema-sharederrorresponse-b33e216723) ## Servers - **URL:** `https://api.stibee.com/v2` ## Authentication - **AccessToken**: API key in header `AccessToken` ## Tags ### 이메일 프로, 엔터프라이즈 요금제에서 사용할 수 있는 API입니다. ### 이메일 - 콘텐츠 프로, 엔터프라이즈 요금제에서 사용할 수 있는 API입니다. ### 이메일 - 태그 프로, 엔터프라이즈 요금제에서 사용할 수 있는 API입니다. ### 주소록 엔터프라이즈 요금제에서 사용할 수 있는 API입니다. ### 주소록 - 구독자 스탠다드, 프로, 엔터프라이즈 요금제에서 사용할 수 있는 API입니다. ### 주소록 - 그룹 프로, 엔터프라이즈 요금제에서 사용할 수 있는 API입니다. ### 주소록 - 발신자 이메일 주소 엔터프라이즈 요금제에서 사용할 수 있는 API입니다. ## Operations ### 이메일 목록 조회 - **Method:** `GET` - **Path:** `/emails` - **Operation ID:** `getEmails` - **Tags:** 이메일 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 워크스페이스에 생성된 이메일 목록을 조회합니다. #### Query parameters - **`tagIds`**: `integer`, format: `int` - **`listId`**: `integer`, format: `int` - **`offset`**: `integer`, format: `int`, default: `0`, minimum: `0` - **`limit`**: `integer`, format: `int`, default: `20`, minimum: `1`, maximum: `100` 한 번에 가져올 데이터의 최대 개수 (최대 100) - **`emailId`**: `integer`, format: `int` 특정 이메일 아이디로 필터링 - **`ids`**: `string` 조회할 이메일 아이디 목록(쉼표로 구분). 예) "1024,1025" - 한 번에 최대 100개까지 지정할 수 있습니다. - 중복된 아이디는 하나로 처리됩니다. - 숫자가 아니거나 0 이하인 값이 있으면 400 오류가 발생합니다. - `emailId`와 함께 지정하면 두 조건을 모두 만족하는 이메일만 조회됩니다. **Example: default** ```json "1024,1025" ``` - **`statuses`**: `string` 조회할 이메일 상태(쉼표로 구분). 예) "0,3" 또는 "WRITING,SENT" - 상태 코드(숫자)와 상태 이름(`statusName`) 중 어느 쪽으로도 요청할 수 있습니다. - 상태 이름은 대소문자를 구분하지 않습니다. 예) "writing,sent" - 토큰 앞뒤 공백은 허용됩니다. 예) "0, 3" - 이름도 숫자도 아닌 값은 무시됩니다. 이 경우 400 오류는 발생하지 않습니다. - 위 목록에 없는 숫자도 무시되지 않고 조회 조건에 그대로 사용됩니다. - 0 (WRITING): 작성 중 - 1 (RESERVED): 예약 - 3 (SENT): 발송 완료 - 10 (AUTO_DRAFT): 자동 작성 중 - 11 (AUTO_SENDING): 자동 발송 중 - 12 (AUTO_PAUSED): 자동 일시중지 - 13 (AUTO_STOPPED): 자동 중지 - 15 (AUTO_RESERVED): 자동 예약 - 21 (PROCESSING): 처리 중 - 22 (SENDING): 발송 중 - 23 (SENDING_DELAYED): 발송 지연 - 41 (FAILED): 실패 - 42 (SPAM): 스팸 ※ 21·22·23은 발송이 진행되는 동안 잠깐 거치는 상태입니다. 같은 조건으로 다시 조회하면 이미 다음 상태(예: 3 발송 완료)로 넘어가 목록에서 빠질 수 있습니다. **Example: ByCode** 상태 코드로 요청하는 경우 ```json "0,3" ``` **Example: ByName** 상태 이름으로 요청하는 경우 ```json "WRITING,SENT" ``` - **`types`**: `string` 조회할 이메일 종류(쉼표로 구분). 예) "1,2" 또는 "NORMAL,AB_TEST" - 종류 코드(숫자)와 종류 이름(`typeName`) 중 어느 쪽으로도 요청할 수 있습니다. - 종류 이름은 대소문자를 구분하지 않습니다. 예) "normal,ab_test" - 토큰 앞뒤 공백은 허용됩니다. 예) "1, 2" - 이름도 숫자도 아닌 값은 무시됩니다. 이 경우 400 오류는 발생하지 않습니다. - 위 목록에 없는 숫자도 무시되지 않고 조회 조건에 그대로 사용됩니다. - 지정하지 않으면 모든 종류를 반환합니다. - 1 (NORMAL): 일반 이메일 - 2 (AB_TEST): A/B 이메일 - 3 (AUTO_MAIL): 자동 이메일 - 4 (AUTO_SMS): 자동 문자 **Example: ByCode** 종류 코드로 요청하는 경우 ```json "1,2" ``` **Example: ByName** 종류 이름으로 요청하는 경우 ```json "NORMAL,AB_TEST" ``` - **`sentAfter`**: `string` 이 시각 **이후**에 발송된 이메일만 조회합니다(해당 시각 제외). - "2026-05-01 00:00:00" 형식으로 날짜와 시각을 모두 지정해야 합니다. - 아직 발송되지 않은 이메일은 조회되지 않습니다. **Example: default** ```json "2026-05-01 00:00:00" ``` - **`sentBefore`**: `string` 이 시각 **이하**에 발송된 이메일만 조회합니다(해당 시각 포함). - `sentAfter`와 함께 사용해야 합니다. 단독으로 지정하면 400 오류가 발생합니다. - "2026-05-31 23:59:59" 형식으로 날짜와 시각을 모두 지정해야 합니다. **Example: default** ```json "2026-05-31 23:59:59" ``` - **`sortBy`**: `string`, possible values: `"createdTime", "modifiedTime", "sentTime"` 정렬 기준 필드. - createdTime: 생성일시 - modifiedTime: 수정일시 - sentTime: 발송일시 - 대소문자를 구분하지 않으며 앞뒤 공백은 무시됩니다. 예) "SENTTIME" - 위 목록에 없는 값을 보내면 400 오류가 발생합니다. - `sortBy` 를 지정하고 `sortOrder` 를 생략하면 `desc` 로 정렬됩니다. - `sortBy` 를 생략하고 `sortOrder` 만 지정하면 `createdTime` 기준으로 정렬됩니다. - 둘 다 생략하면 정렬 순서를 보장하지 않습니다. - **`sortOrder`**: `string`, possible values: `"asc", "desc"` 정렬 순서. 기준 필드는 `sortBy` 로 지정합니다. - 대소문자를 구분하지 않습니다. 예) "DESC" - `sortBy` 를 지정하고 `sortOrder` 를 생략하면 `desc` 로 정렬됩니다. - asc 또는 desc 가 아닌 값을 보내면 400 오류가 발생합니다. #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | ------------------------------- | ------------------------------------------ | ---------------------------------- | ------------------------------------------------------------------------------------------------ | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestNotNumber` | offset 또는 limit이 숫자가 아닌 경우 | `{"values":{"message":"offset이 숫자가 아닙니다."}}` | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestNegativeOffset` | offset이 0보다 작은 경우 | `{"values":{"message":"offset이 0 이상이어야 합니다."}}` | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestInvalidLimit` | limit이 1보다 작은 경우 | `{"values":{"message":"limit이 1 이상이어야 합니다."}}` | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestInvalidSortOrder` | sortOrder가 asc 또는 desc가 아닌 경우 | `{"values":{"message":"sortOrder는 asc 또는 desc만 가능합니다. (대소문자를 구분하지 않습니다)"}}` | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestInvalidSortBy` | sortBy가 허용된 값이 아닌 경우 | `{"values":{"message":"sortBy는 createdTime, modifiedTime, sentTime을 지원합니다. (대소문자를 구분하지 않습니다)"}}` | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestInvalidIds` | ids에 숫자가 아니거나 0 이하인 값이 있는 경우 | `{"values":{"message":"이메일 아이디는 쉼표로 구분한 양의 정수여야 합니다."}}` | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestSentBeforeWithoutSentAfter` | sentBefore만 지정하고 sentAfter를 생략한 경우 | `{"values":{"message":"sentBefore는 sentAfter와 함께 사용해야 합니다."}}` | | `400` | `Errors.Data.InvalidDateFormat` | `InvalidDateFormatSentAfter` | sentAfter가 날짜와 시각을 모두 포함하지 않는 경우 | `{"values":{"message":"sentAfter는 2026-05-01 00:00:00 형식이어야 합니다."}}` | | `400` | `Errors.Data.InvalidDateFormat` | `InvalidDateFormatSentBefore` | sentBefore가 날짜와 시각을 모두 포함하지 않는 경우 | `{"values":{"message":"sentBefore는 2026-05-31 23:59:59 형식이어야 합니다."}}` | | `400` | `Errors.Data.InvalidDateRange` | `InvalidDateRange` | sentAfter가 sentBefore보다 뒤인 경우 | | | `400` | `Errors.Data.LimitExceeded` | `LimitExceeded` | 한 번에 조회할 수 있는 개수를 초과한 경우 | `{"values":{"message":"이메일 목록 조회는 한 번에 최대 100건까지입니다."}}` | | `400` | `Errors.Data.LimitExceeded` | `LimitExceededTooManyIds` | ids를 101개 이상 지정한 경우 | `{"values":{"message":"ids는 한 번에 최대 100개까지 지정할 수 있습니다."}}` | ##### 200 이메일 목록 조회 성공 **Content type:** `application/json` [GetEmailsResponse](#scalar-schema-getemailsresponse) **Example: default** ```json { "total": 1, "offset": 0, "limit": 20, "items": [ { "id": 123456, "owner": "abcd1234-ab12-cd34-ef56-abcdef123456", "status": 3, "statusName": "SENT", "type": 1, "typeName": "NORMAL", "listId": 1234, "subject": "이메일 제목", "senderEmail": "gildong.go@stibee.com", "senderName": "고길동", "permanentLink": "https://stib.ee/2eYF", "segmentIds": [ 1234 ], "groupIds": null, "sentTime": "2024-07-23T18:43:03+09:00", "createdTime": "2024-07-19T17:56:06+09:00" } ] } ``` ##### 400 실패 **Content type:** `application/json` [GetEmailsErrorResponse](#scalar-schema-getemailserrorresponse) **Example: InvalidRequestNotNumber** offset 또는 limit이 숫자가 아닌 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "offset이 숫자가 아닙니다." } } ``` **Example: InvalidRequestNegativeOffset** offset이 0보다 작은 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "offset이 0 이상이어야 합니다." } } ``` **Example: InvalidRequestInvalidLimit** limit이 1보다 작은 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "limit이 1 이상이어야 합니다." } } ``` **Example: InvalidRequestInvalidSortOrder** sortOrder가 asc 또는 desc가 아닌 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "sortOrder는 asc 또는 desc만 가능합니다. (대소문자를 구분하지 않습니다)" } } ``` **Example: InvalidRequestInvalidSortBy** sortBy가 허용된 값이 아닌 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "sortBy는 createdTime, modifiedTime, sentTime을 지원합니다. (대소문자를 구분하지 않습니다)" } } ``` **Example: InvalidRequestInvalidIds** ids에 숫자가 아니거나 0 이하인 값이 있는 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "이메일 아이디는 쉼표로 구분한 양의 정수여야 합니다." } } ``` **Example: InvalidRequestSentBeforeWithoutSentAfter** sentBefore만 지정하고 sentAfter를 생략한 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "sentBefore는 sentAfter와 함께 사용해야 합니다." } } ``` **Example: InvalidDateFormatSentAfter** sentAfter가 날짜와 시각을 모두 포함하지 않는 경우 ```json { "code": "Errors.Data.InvalidDateFormat", "httpStatusCode": 400, "message": "날짜 형식이 올바르지 않습니다.", "values": { "message": "sentAfter는 2026-05-01 00:00:00 형식이어야 합니다." } } ``` **Example: InvalidDateFormatSentBefore** sentBefore가 날짜와 시각을 모두 포함하지 않는 경우 ```json { "code": "Errors.Data.InvalidDateFormat", "httpStatusCode": 400, "message": "날짜 형식이 올바르지 않습니다.", "values": { "message": "sentBefore는 2026-05-31 23:59:59 형식이어야 합니다." } } ``` **Example: InvalidDateRange** sentAfter가 sentBefore보다 뒤인 경우 ```json { "code": "Errors.Data.InvalidDateRange", "httpStatusCode": 400, "message": "날짜 범위가 올바르지 않습니다." } ``` **Example: LimitExceeded** 한 번에 조회할 수 있는 개수를 초과한 경우 ```json { "code": "Errors.Data.LimitExceeded", "httpStatusCode": 400, "message": "요청 제한을 초과하였습니다.", "values": { "message": "이메일 목록 조회는 한 번에 최대 100건까지입니다." } } ``` **Example: LimitExceededTooManyIds** ids를 101개 이상 지정한 경우 ```json { "code": "Errors.Data.LimitExceeded", "httpStatusCode": 400, "message": "요청 제한을 초과하였습니다.", "values": { "message": "ids는 한 번에 최대 100개까지 지정할 수 있습니다." } } ``` ### 일반 이메일 생성 - **Method:** `POST` - **Path:** `/emails` - **Operation ID:** `createEmail` - **Tags:** 이메일 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 새로운 일반 이메일을 생성합니다. - 자동 이메일은 지원하지 않습니다. #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | -------------- | ----------------- | --------- | ----------------- | ---------- | ------ | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `subject` | `필수 (부모 객체 존재 시)` | `string` | | 이메일 제목 | | | `senderEmail` | `필수 (부모 객체 존재 시)` | `string` | `format: "email"` | 발신자 이메일 주소 | | | `senderName` | `필수 (부모 객체 존재 시)` | `string` | | 발신자 이름 | | | `listId` | `필수 (부모 객체 존재 시)` | `integer` | | 발송 대상 주소록 | | | `segmentIds` | `선택` | `array` | | 발송 대상 세그먼트 | | | `segmentIds[]` | `배열 원소 스키마` | `integer` | | | | | `groupIds` | `선택` | `array` | | 발송 대상 그룹 | | | `groupIds[]` | `배열 원소 스키마` | `integer` | | | | **Content type:** `application/json` [CreateEmailRequest](#scalar-schema-createemailrequest) **Example: default** ```json { "subject": "이메일 제목", "senderEmail": "gildong.go@stibee.com", "senderName": "고길동", "listId": 1234 } ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | ---------------------------------------------------------------- | ----- | | `400` | `Errors.Email.WrongEmailType` | `WrongEmailType` | 자동 이메일에 대해 요청한 경우 | | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | listId, segmentIds, groupIds의 소유자가 아니거나, 사용할 수 없는 발신자 이메일 주소인 경우 | | ##### 200 일반 이메일 생성 성공 **Content type:** `application/json` [CreateEmailResponse](#scalar-schema-createemailresponse) ##### 400 실패 **Content type:** `application/json` [CreateEmailErrorResponse](#scalar-schema-createemailerrorresponse) **Example: WrongEmailType** 자동 이메일에 대해 요청한 경우 ```json { "code": "Errors.Email.WrongEmailType", "httpStatusCode": 400, "message": "일반 이메일이 아닙니다." } ``` **Example: PermissionDenied** listId, segmentIds, groupIds의 소유자가 아니거나, 사용할 수 없는 발신자 이메일 주소인 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 일반 이메일 삭제 - **Method:** `DELETE` - **Path:** `/emails/{id}` - **Operation ID:** `deleteEmail` - **Tags:** 이메일 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 일반 이메일을 삭제합니다. - 자동 이메일은 지원하지 않습니다. #### Path parameters - **`id` (required)**: `integer` 삭제할 이메일 아이디 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 이메일의 소유자가 아닌 경우 | | ##### 200 일반 이메일 삭제 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) **Example: PermissionDenied** 이메일의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 이메일 정보 조회 - **Method:** `GET` - **Path:** `/emails/{id}` - **Operation ID:** `getEmail` - **Tags:** 이메일 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 이메일의 정보(이메일 제목, 발신자 이름, 발송 대상 주소록 등)를 조회합니다. #### Path parameters - **`id` (required)**: `integer`, format: `int` 이메일 아이디 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | ------------------------------------------------ | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 이메일의 소유자가 아닌 경우, 이메일이 존재하지 않는 경우, 이미 삭제된 이메일인 경우 | | ##### 200 성공 **Content type:** `application/json` [GetEmailResponse](#scalar-schema-getemailresponse) **Example: NormalEmail** 일반 이메일 ```json { "id": 123456, "owner": "abcd1234-ab12-cd34-ef56-abcdef123456", "status": 3, "statusName": "SENT", "type": 1, "typeName": "NORMAL", "listId": 1234, "subject": "이메일 제목", "senderEmail": "gildong.go@stibee.com", "senderName": "고길동", "permanentLink": "https://stib.ee/2eYF", "segmentIds": [ 1234 ], "groupIds": null, "sentTime": "2024-07-23T18:43:03+09:00", "createdTime": "2024-07-19T17:56:06+09:00" } ``` **Example: ABTestEmail** A/B 이메일 ```json { "id": 123456, "owner": "abcd1234-ab12-cd34-ef56-abcdef123456", "status": 3, "statusName": "SENT", "type": 2, "typeName": "AB_TEST", "listId": 1234, "subject": "이메일 제목", "senderEmail": "gildong.go@stibee.com", "senderName": "고길동", "permanentLink": "https://stib.ee/2eYF", "segmentIds": [ 1234 ], "groupIds": null, "sentTime": "2024-07-23T18:43:03+09:00", "createdTime": "2024-07-19T17:56:06+09:00", "subType": 1, "subjectB": "B안 제목", "senderNameB": "고길동B", "permanentLinkSecondary": "https://stib.ee/3fZG", "sentTimeB": "2024-07-23T20:43:03+09:00", "abRatio": 50 } ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) **Example: PermissionDenied** 이메일의 소유자가 아닌 경우, 이메일이 존재하지 않는 경우, 이미 삭제된 이메일인 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 일반 이메일 정보 수정 - **Method:** `PUT` - **Path:** `/emails/{id}` - **Operation ID:** `updateEmail` - **Tags:** 이메일 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 일반 이메일의 정보(이메일 제목, 발신자 이름, 발송 대상 주소록 등)를 수정합니다. - 작성 중 상태인 일반 이메일의 정보만 수정할 수 있습니다. - 자동 이메일은 지원하지 않습니다. #### Path parameters - **`id` (required)**: `integer` 수정할 이메일 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | -------------- | -------------- | --------- | -------------------------- | ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `$` | `본문 전송 여부와 별개` | `object` | | | `{"type":1,"subType":2,"abRatio":60,"subject":"이메일 제목","subjectA":"이메일 제목 A","subjectB":"이메일 제목 B","senderEmail":"gildong.go@stibee.com","senderName":"고길동","senderNameA":"둘리","senderNameB":"희동이","listId":123,"segmentIds":[1,2,3],"groupIds":[4,5,6]}` | | `type` | `선택` | `integer` | | 이메일 타입 | `1` | | `subType` | `선택` | `integer` | | 이메일 서브타입 | `2` | | `abRatio` | `선택` | `integer` | `minimum: 0; maximum: 100` | A/B 테스트 비율 | `60` | | `subject` | `선택` | `string` | | 이메일 제목 | `"Email Subject"` | | `subjectA` | `선택` | `string` | | A/B 테스트용 A 제목 | `"Subject A"` | | `subjectB` | `선택` | `string` | | A/B 테스트용 B 제목 | `"Subject B"` | | `senderEmail` | `선택` | `string` | `format: "email"` | 발신자 이메일 | `"gildong.go@stibee.com"` | | `senderName` | `선택` | `string` | | 발신자 이름 | `"Sender Name"` | | `senderNameA` | `선택` | `string` | | A/B 테스트용 A 발신자 이름 | `"Sender Name A"` | | `senderNameB` | `선택` | `string` | | A/B 테스트용 B 발신자 이름 | `"Sender Name B"` | | `listId` | `선택` | `integer` | | 주소록 아이디 | `123` | | `segmentIds` | `선택` | `array` | | 세그먼트 아이디 목록 | `[1,2,3]` | | `segmentIds[]` | `배열 원소 스키마` | `integer` | | | | | `groupIds` | `선택` | `array` | | 그룹 아이디 목록 | `[4,5,6]` | | `groupIds[]` | `배열 원소 스키마` | `integer` | | | | **Content type:** `application/json` [UpdateEmailRequest](#scalar-schema-updateemailrequest) **Example:** ```json { "type": 1, "subType": 2, "abRatio": 60, "subject": "이메일 제목", "subjectA": "이메일 제목 A", "subjectB": "이메일 제목 B", "senderEmail": "gildong.go@stibee.com", "senderName": "고길동", "senderNameA": "둘리", "senderNameB": "희동이", "listId": 123, "segmentIds": [ 1, 2, 3 ], "groupIds": [ 4, 5, 6 ] } ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | -------------------------------------------------------------------------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 이메일의 소유자가 아니거나, listId, segmentIds, groupIds의 소유자가 아니거나, 사용할 수 없는 발신자 이메일 주소인 경우 | | | `400` | `Errors.Email.WrongEmailType` | `WrongEmailType` | 자동 이메일에 대해 요청한 경우 | | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 작성 중 상태가 아닌 경우 | | ##### 200 일반 이메일 정보 수정 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [UpdateEmailErrorResponse](#scalar-schema-updateemailerrorresponse) **Example: PermissionDenied** 이메일의 소유자가 아니거나, listId, segmentIds, groupIds의 소유자가 아니거나, 사용할 수 없는 발신자 이메일 주소인 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: WrongEmailType** 자동 이메일에 대해 요청한 경우 ```json { "code": "Errors.Email.WrongEmailType", "httpStatusCode": 400, "message": "일반 이메일이 아닙니다." } ``` **Example: InvalidRequest** 작성 중 상태가 아닌 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` ### 일반 이메일 발송 예약 취소 - **Method:** `POST` - **Path:** `/emails/{id}/cancel-reserve` - **Operation ID:** `cancelReserveEmail` - **Tags:** 이메일 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 예약된 일반 이메일 발송을 취소합니다. - 자동 이메일은 지원하지 않습니다. #### Path parameters - **`id` (required)**: `integer` 예약 취소할 이메일 아이디 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 이메일의 소유자가 아닌 경우 | | ##### 200 일반 이메일 발송 예약 취소 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) **Example: PermissionDenied** 이메일의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 이메일 복사 - **Method:** `POST` - **Path:** `/emails/{id}/copy` - **Operation ID:** `copyEmail` - **Tags:** 이메일 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 일반 이메일을 복사해 새로운 일반 이메일을 생성합니다. - 자동 이메일은 지원하지 않습니다. #### Path parameters - **`id` (required)**: `integer` 복사할 이메일 아이디 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 이메일의 소유자가 아닌 경우 | | ##### 200 이메일 복사 성공 **Content type:** `application/json` [CreatedCopiedEmailResponse](#scalar-schema-createdcopiedemailresponse) ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) **Example: PermissionDenied** 이메일의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 이메일 상세 통계 조회 - **Method:** `GET` - **Path:** `/emails/{id}/logs` - **Operation ID:** `getEmailLogs` - **Tags:** 이메일 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 이메일의 상세 통계(발송 성공한 구독자 목록, 오픈한 구독자 목록 등)를 조회합니다. #### Path parameters - **`id` (required)**: `integer` 이메일 아이디 #### Query parameters - **`offset`**: `integer`, default: `0`, minimum: `0` 현재 데이터 조회가 시작되는 위치 - **`limit`**: `integer`, default: `20`, minimum: `1`, maximum: `1000` 한 번에 가져올 데이터의 최대 개수 (최대 1000) - **`actions`**: `string` 조회할 구독자 활동(쉼표로 구분). 예) "O,C" 또는 "OPENED,CLICKED" - 활동 코드(`action`)와 활동 이름(`actionName`) 중 어느 쪽으로도 요청할 수 있습니다. - 활동 이름은 대소문자를 구분하지 않습니다. 예) "opened,clicked" - 토큰 앞뒤 공백은 허용됩니다. 예) "O, C" - 같은 활동을 코드와 이름으로 함께 보내면 하나로 처리됩니다. 예) "B,HARD_BOUNCED" - 알 수 없는 값은 무시됩니다. 이 경우 400 오류는 발생하지 않습니다. - 보낸 값이 전부 알 수 없는 값이면 필터를 지정하지 않은 것과 같습니다. - 지정하지 않으면 모든 활동을 조회합니다. - P (DELIVERED): 발송 성공 - F (SOFT_BOUNCED): 발송 실패, 소프트바운스 - A (HARD_BOUNCED_DELETED): 발송 실패, 하드바운스, 주소록 자동삭제 적용 - B (HARD_BOUNCED): 발송 실패, 하드바운스, 주소록 자동삭제 미적용 - D (UNSUBSCRIBED): 수신 거부 - O (OPENED): 이메일 오픈 - C (CLICKED): 이메일 본문 내 링크 클릭 - G (DONATED): 기부 완료 - V (DONATION_REDIRECT): 기부 페이지 유입 **Example: ByCode** 활동 코드로 요청하는 경우 ```json "O,C" ``` **Example: ByName** 활동 이름으로 요청하는 경우 ```json "OPENED,CLICKED" ``` - **`subscribers`**: `string` 조회할 구독자의 이메일 주소(쉼표로 구분). 지정하면 해당 구독자들의 로그만 조회합니다. - 한 번에 최대 30명까지 지정할 수 있습니다. - 주소가 정확히 일치하는 로그만 조회합니다. 부분 검색은 지원하지 않습니다. - `actions`와 함께 쓸 수 있습니다. 예) "subscribers=\&actions=O" - 앞뒤 공백은 무시되고, 같은 주소를 여러 번 넣어도 한 번만 조회합니다. - 여러 명을 지정하면 로그 아이디 오름차순으로 반환되므로, 한 구독자의 로그가 `limit`을 채우면 다른 구독자의 로그는 다음 페이지에 나옵니다. `offset`으로 끝까지 넘겨야 전원의 로그를 볼 수 있습니다. - 해당 구독자들의 로그가 없으면 빈 목록과 `total: 0`을 반환합니다. **Example: default** ```json "gildong.go@stibee.com,dooly@stibee.com" ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | ---------------------------- | ------------------------------ | -------------------------- | ----------------------------------------------------------------- | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestNotNumber` | offset 또는 limit이 숫자가 아닌 경우 | `{"values":{"message":"offset이 숫자가 아닙니다."}}` | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestNegativeOffset` | offset이 0보다 작은 경우 | `{"values":{"message":"offset이 0 이상이어야 합니다."}}` | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestInvalidLimit` | limit이 1보다 작은 경우 | `{"values":{"message":"limit이 1 이상이어야 합니다."}}` | | `400` | `Errors.Data.LimitExceeded` | `LimitExceeded` | 한 번에 조회할 수 있는 개수를 초과한 경우 | `{"values":{"message":"이메일 로그 조회는 한 번에 최대 1000건까지입니다."}}` | | `400` | `Errors.Data.LimitExceeded` | `TooManySubscribers` | subscribers를 31명 이상 지정한 경우 | `{"values":{"message":"subscribers는 한 번에 최대 30명까지 지정할 수 있습니다."}}` | ##### 200 이메일 상세 통계 조회 성공 **Content type:** `application/json` [EmailLogsResponse](#scalar-schema-emaillogsresponse) **Example: default** ```json { "total": 1, "offset": 0, "limit": 20, "items": [ { "id": 1, "subscriber": "gildong.go@stibee.com", "action": "P", "actionName": "DELIVERED", "value": "", "value2": "250\nok", "createdTime": "2024-07-23T18:43:08+09:00" } ] } ``` ##### 400 실패 **Content type:** `application/json` [GetEmailLogsErrorResponse](#scalar-schema-getemaillogserrorresponse) **Example: InvalidRequestNotNumber** offset 또는 limit이 숫자가 아닌 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "offset이 숫자가 아닙니다." } } ``` **Example: InvalidRequestNegativeOffset** offset이 0보다 작은 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "offset이 0 이상이어야 합니다." } } ``` **Example: InvalidRequestInvalidLimit** limit이 1보다 작은 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "limit이 1 이상이어야 합니다." } } ``` **Example: LimitExceeded** 한 번에 조회할 수 있는 개수를 초과한 경우 ```json { "code": "Errors.Data.LimitExceeded", "httpStatusCode": 400, "message": "요청 제한을 초과하였습니다.", "values": { "message": "이메일 로그 조회는 한 번에 최대 1000건까지입니다." } } ``` **Example: TooManySubscribers** subscribers를 31명 이상 지정한 경우 ```json { "code": "Errors.Data.LimitExceeded", "httpStatusCode": 400, "message": "요청 제한을 초과하였습니다.", "values": { "message": "subscribers는 한 번에 최대 30명까지 지정할 수 있습니다." } } ``` ### 일반 이메일 발송 예약 - **Method:** `POST` - **Path:** `/emails/{id}/reserve` - **Operation ID:** `reserveEmail` - **Tags:** 이메일 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 일반 이메일을 발송 예약합니다. - 자동 이메일은 지원하지 않습니다. #### Path parameters - **`id` (required)**: `integer` 예약 발송할 이메일 아이디 #### Query parameters - **`reserveTime` (required)**: `string`, pattern: `^\d{14}$` 발송 시간(YYYYMMDDhhmmss 형식, 대한민국 표준시(UTC+9:00) 기준) **Example: default** ```json "20250501143040" ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | ------------------------------------------- | ------------------------------- | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 이메일, 주소록, 세그먼트, 그룹의 소유자가 아닌 경우 | | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestWrongFormat` | reserveTime이 YYYYMMDDhhmmss 형식이 아닌 경우 | `{"values":{"message":"잘못된 형식의 reserveTime"}}` | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestPastTime` | reserveTime이 과거 시간인 경우 | `{"values":{"message":"과거 시간은 예약할 수 없습니다. 현재시간: 2025-05-01 14:30:40 +0900 KST"}}` | | `400` | `Errors.Email.WrongStatus` | `WrongStatus` | 발송할 수 있는 상태가 아닌 경우 | | | `400` | `Errors.List.ExceededSubscribers` | `ExceededSubscribers` | 요금제의 구독자 수 한도를 초과한 경우 | | | `400` | `Errors.Email.Spamer` | `Spamer` | 스팸 발송자로 분류된 경우 | | | `400` | `Errors.Email.EmptySubscriber` | `EmptySubscriber` | 발송 대상 구독자가 0명인 경우 | | | `400` | `Errors.Service.NeedProPlan` | `NeedProPlan` | 프로 요금제 이상에서만 사용할 수 있는 기능을 사용한 경우 | | | `400` | `Errors.List.NoEmailActionSegmentAuthority` | `NoEmailActionSegmentAuthority` | 구독자 활동 조건 세그먼트를 사용했으나 요금제 권한이 없는 경우 | | | `400` | `Errors.List.TooManyGroups` | `TooManyGroups` | 그룹 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 \`values.maxCount\`로 전달됩니다. | `{"values":{"maxCount":30}}` | | `400` | `Errors.List.ExceededSubscriberVarLimit` | `ExceededSubscriberVarLimit` | 사용자 정의 필드 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 \`values.maxCount\`로 전달됩니다. | `{"values":{"maxCount":30}}` | | `400` | `Errors.List.SegmentExceededLimit` | `SegmentExceededLimit` | 세그먼트 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 \`values.maxCount\`로 전달됩니다. | `{"values":{"maxCount":5}}` | | `400` | `Errors.Email.ExceededAutomailCountLimit` | `ExceededAutomailCountLimit` | 자동 이메일 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 \`values.maxCount\`로 전달됩니다. | `{"values":{"maxCount":1}}` | | `400` | `Errors.Email.IncompleteEmail` | `IncompleteEmail` | 제목, 발신자, 콘텐츠 등이 채워지지 않아 이메일이 완성되지 않은 경우 | | ##### 200 일반 이메일 발송 예약 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [ReserveEmailErrorResponse](#scalar-schema-reserveemailerrorresponse) **Example: PermissionDenied** 이메일, 주소록, 세그먼트, 그룹의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: InvalidRequestWrongFormat** reserveTime이 YYYYMMDDhhmmss 형식이 아닌 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "잘못된 형식의 reserveTime" } } ``` **Example: InvalidRequestPastTime** reserveTime이 과거 시간인 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "과거 시간은 예약할 수 없습니다. 현재시간: 2025-05-01 14:30:40 +0900 KST" } } ``` **Example: WrongStatus** 발송할 수 있는 상태가 아닌 경우 ```json { "code": "Errors.Email.WrongStatus", "httpStatusCode": 400, "message": "이메일 상태를 확인 하세요." } ``` **Example: ExceededSubscribers** 요금제의 구독자 수 한도를 초과한 경우 ```json { "code": "Errors.List.ExceededSubscribers", "httpStatusCode": 400, "message": "구독자가 초과 하였습니다." } ``` **Example: Spamer** 스팸 발송자로 분류된 경우 ```json { "code": "Errors.Email.Spamer", "httpStatusCode": 400, "message": "스패머" } ``` **Example: EmptySubscriber** 발송 대상 구독자가 0명인 경우 ```json { "code": "Errors.Email.EmptySubscriber", "httpStatusCode": 400, "message": "구독자가 0명입니다." } ``` **Example: NeedProPlan** 프로 요금제 이상에서만 사용할 수 있는 기능을 사용한 경우 ```json { "code": "Errors.Service.NeedProPlan", "httpStatusCode": 400, "message": "프로 요금제 이상부터 사용할 수 있습니다." } ``` **Example: NoEmailActionSegmentAuthority** 구독자 활동 조건 세그먼트를 사용했으나 요금제 권한이 없는 경우 ```json { "code": "Errors.List.NoEmailActionSegmentAuthority", "httpStatusCode": 400, "message": "구독자 활동 조건 세그먼트는 프로 요금제에서 사용할 수 있습니다." } ``` **Example: TooManyGroups** 그룹 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 `values.maxCount`로 전달됩니다. ```json { "code": "Errors.List.TooManyGroups", "httpStatusCode": 400, "message": "그룹은 최대 {maxCount}개 까지만 만들 수 있습니다.", "values": { "maxCount": 30 } } ``` **Example: ExceededSubscriberVarLimit** 사용자 정의 필드 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 `values.maxCount`로 전달됩니다. ```json { "code": "Errors.List.ExceededSubscriberVarLimit", "httpStatusCode": 400, "message": "사용자 정의 필드는 최대 {maxCount}개 까지만 만들 수 있습니다.", "values": { "maxCount": 30 } } ``` **Example: SegmentExceededLimit** 세그먼트 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 `values.maxCount`로 전달됩니다. ```json { "code": "Errors.List.SegmentExceededLimit", "httpStatusCode": 400, "message": "세그먼트는 최대 {maxCount}개 까지만 만들 수 있습니다.", "values": { "maxCount": 5 } } ``` **Example: ExceededAutomailCountLimit** 자동 이메일 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 `values.maxCount`로 전달됩니다. ```json { "code": "Errors.Email.ExceededAutomailCountLimit", "httpStatusCode": 400, "message": "자동이메일은 최대 {maxCount}개까지만 실행할 수 있습니다.", "values": { "maxCount": 1 } } ``` **Example: IncompleteEmail** 제목, 발신자, 콘텐츠 등이 채워지지 않아 이메일이 완성되지 않은 경우 ```json { "code": "Errors.Email.IncompleteEmail", "httpStatusCode": 400, "message": "이메일이 완성되지 않았습니다." } ``` ### 일반 이메일 발송 - **Method:** `POST` - **Path:** `/emails/{id}/send` - **Operation ID:** `sendEmail` - **Tags:** 이메일 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 일반 이메일을 발송합니다. - 자동 이메일은 지원하지 않습니다. #### Path parameters - **`id` (required)**: `integer` 발송할 이메일 아이디 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | ------------------------------------------- | ------------------------------- | ---------------------------------------------------------------------- | ---------------------------- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 이메일, 주소록, 세그먼트, 그룹의 소유자가 아닌 경우 | | | `400` | `Errors.Email.WrongStatus` | `WrongStatus` | 발송할 수 있는 상태가 아닌 경우 | | | `400` | `Errors.List.ExceededSubscribers` | `ExceededSubscribers` | 요금제의 구독자 수 한도를 초과한 경우 | | | `400` | `Errors.Email.Spamer` | `Spamer` | 스팸 발송자로 분류된 경우 | | | `400` | `Errors.Email.EmptySubscriber` | `EmptySubscriber` | 발송 대상 구독자가 0명인 경우 | | | `400` | `Errors.Service.NeedProPlan` | `NeedProPlan` | 프로 요금제 이상에서만 사용할 수 있는 기능을 사용한 경우 | | | `400` | `Errors.List.NoEmailActionSegmentAuthority` | `NoEmailActionSegmentAuthority` | 구독자 활동 조건 세그먼트를 사용했으나 요금제 권한이 없는 경우 | | | `400` | `Errors.List.TooManyGroups` | `TooManyGroups` | 그룹 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 \`values.maxCount\`로 전달됩니다. | `{"values":{"maxCount":30}}` | | `400` | `Errors.List.ExceededSubscriberVarLimit` | `ExceededSubscriberVarLimit` | 사용자 정의 필드 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 \`values.maxCount\`로 전달됩니다. | `{"values":{"maxCount":30}}` | | `400` | `Errors.List.SegmentExceededLimit` | `SegmentExceededLimit` | 세그먼트 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 \`values.maxCount\`로 전달됩니다. | `{"values":{"maxCount":5}}` | | `400` | `Errors.Email.ExceededAutomailCountLimit` | `ExceededAutomailCountLimit` | 자동 이메일 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 \`values.maxCount\`로 전달됩니다. | `{"values":{"maxCount":1}}` | | `400` | `Errors.Email.IncompleteEmail` | `IncompleteEmail` | 제목, 발신자, 콘텐츠 등이 채워지지 않아 이메일이 완성되지 않은 경우 | | ##### 200 일반 이메일 발송 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SendEmailErrorResponse](#scalar-schema-sendemailerrorresponse) **Example: PermissionDenied** 이메일, 주소록, 세그먼트, 그룹의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: WrongStatus** 발송할 수 있는 상태가 아닌 경우 ```json { "code": "Errors.Email.WrongStatus", "httpStatusCode": 400, "message": "이메일 상태를 확인 하세요." } ``` **Example: ExceededSubscribers** 요금제의 구독자 수 한도를 초과한 경우 ```json { "code": "Errors.List.ExceededSubscribers", "httpStatusCode": 400, "message": "구독자가 초과 하였습니다." } ``` **Example: Spamer** 스팸 발송자로 분류된 경우 ```json { "code": "Errors.Email.Spamer", "httpStatusCode": 400, "message": "스패머" } ``` **Example: EmptySubscriber** 발송 대상 구독자가 0명인 경우 ```json { "code": "Errors.Email.EmptySubscriber", "httpStatusCode": 400, "message": "구독자가 0명입니다." } ``` **Example: NeedProPlan** 프로 요금제 이상에서만 사용할 수 있는 기능을 사용한 경우 ```json { "code": "Errors.Service.NeedProPlan", "httpStatusCode": 400, "message": "프로 요금제 이상부터 사용할 수 있습니다." } ``` **Example: NoEmailActionSegmentAuthority** 구독자 활동 조건 세그먼트를 사용했으나 요금제 권한이 없는 경우 ```json { "code": "Errors.List.NoEmailActionSegmentAuthority", "httpStatusCode": 400, "message": "구독자 활동 조건 세그먼트는 프로 요금제에서 사용할 수 있습니다." } ``` **Example: TooManyGroups** 그룹 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 `values.maxCount`로 전달됩니다. ```json { "code": "Errors.List.TooManyGroups", "httpStatusCode": 400, "message": "그룹은 최대 {maxCount}개 까지만 만들 수 있습니다.", "values": { "maxCount": 30 } } ``` **Example: ExceededSubscriberVarLimit** 사용자 정의 필드 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 `values.maxCount`로 전달됩니다. ```json { "code": "Errors.List.ExceededSubscriberVarLimit", "httpStatusCode": 400, "message": "사용자 정의 필드는 최대 {maxCount}개 까지만 만들 수 있습니다.", "values": { "maxCount": 30 } } ``` **Example: SegmentExceededLimit** 세그먼트 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 `values.maxCount`로 전달됩니다. ```json { "code": "Errors.List.SegmentExceededLimit", "httpStatusCode": 400, "message": "세그먼트는 최대 {maxCount}개 까지만 만들 수 있습니다.", "values": { "maxCount": 5 } } ``` **Example: ExceededAutomailCountLimit** 자동 이메일 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 `values.maxCount`로 전달됩니다. ```json { "code": "Errors.Email.ExceededAutomailCountLimit", "httpStatusCode": 400, "message": "자동이메일은 최대 {maxCount}개까지만 실행할 수 있습니다.", "values": { "maxCount": 1 } } ``` **Example: IncompleteEmail** 제목, 발신자, 콘텐츠 등이 채워지지 않아 이메일이 완성되지 않은 경우 ```json { "code": "Errors.Email.IncompleteEmail", "httpStatusCode": 400, "message": "이메일이 완성되지 않았습니다." } ``` ### 이메일 성과 조회 - **Method:** `GET` - **Path:** `/emails/stats` - **Operation ID:** `getEmailStats` - **Tags:** 이메일 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 100회/분 이메일의 오픈율·클릭율과 발송 대상·성공·실패 수, 오픈·클릭 구독자 수를 여러 건 한 번에 조회합니다. - 두 비율의 분모는 발송에 성공한 구독자 수이며, 웹 화면의 오픈율·클릭율과 같은 값입니다. - 유니크 기준입니다. 한 구독자가 여러 번 열어도 한 번으로 셉니다. - 발송하지 않은 이메일은 모든 값이 0입니다. 발송 여부는 `GET /emails`의 `status`로 확인하세요. - 오픈·클릭 **이벤트 총 횟수**(한 구독자의 중복 포함)가 필요하면 `GET /emails/{id}/logs`에 `actions=O` 또는 `actions=C`를 지정하고 응답의 `total`을 보세요. #### Query parameters - **`ids` (required)**: `string` 조회할 이메일 아이디 목록(쉼표로 구분). 예) "1024,1025" - 한 번에 최대 10개까지 지정할 수 있습니다. - 중복된 아이디는 하나로 처리되며 개수에 포함되지 않습니다. - 하나라도 다른 워크스페이스의 이메일이거나 삭제된 이메일이면 요청 전체가 거절됩니다. **Example: default** ```json "1024,1025" ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------------- | --------------------------------- | --------------------------------------------------------------------------- | | `400` | `Errors.Data.MissingRequiredField` | `MissingRequiredField` | ids를 지정하지 않은 경우 | `{"values":{"message":"ids로 이메일 아이디를 하나 이상 지정해주세요."}}` | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestNotNumber` | ids에 숫자가 아닌 값이 있는 경우 | `{"values":{"message":"이메일 아이디는 쉼표로 구분한 양의 정수여야 합니다."}}` | | `400` | `Errors.Data.LimitExceeded` | `LimitExceeded` | 한 번에 조회할 수 있는 개수를 초과한 경우 | `{"values":{"message":"통계 조회는 한 번에 최대 10건까지입니다. 이메일을 10건 이하로 나눠 요청해주세요."}}` | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 다른 워크스페이스의 이메일이거나 삭제된 이메일이 포함된 경우 | | ##### 200 이메일 성과 조회 성공 **Content type:** `application/json` [GetEmailStatsResponse](#scalar-schema-getemailstatsresponse) **Example: default** ```json { "items": [ { "emailId": 1024, "openRate": 42.5, "clickRate": 8.3 } ] } ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_d07945da9c](#scalar-schema-sharederrorresponse-d07945da9c) **Example: MissingRequiredField** ids를 지정하지 않은 경우 ```json { "code": "Errors.Data.MissingRequiredField", "httpStatusCode": 400, "message": "필수 항목이 누락되었습니다.", "values": { "message": "ids로 이메일 아이디를 하나 이상 지정해주세요." } } ``` **Example: InvalidRequestNotNumber** ids에 숫자가 아닌 값이 있는 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "이메일 아이디는 쉼표로 구분한 양의 정수여야 합니다." } } ``` **Example: LimitExceeded** 한 번에 조회할 수 있는 개수를 초과한 경우 ```json { "code": "Errors.Data.LimitExceeded", "httpStatusCode": 400, "message": "요청 제한을 초과하였습니다.", "values": { "message": "통계 조회는 한 번에 최대 10건까지입니다. 이메일을 10건 이하로 나눠 요청해주세요." } } ``` **Example: PermissionDenied** 다른 워크스페이스의 이메일이거나 삭제된 이메일이 포함된 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 콘텐츠 조회 - **Method:** `GET` - **Path:** `/emails/{id}/content` - **Operation ID:** `getEmailContent` - **Tags:** 이메일 - 콘텐츠 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 이메일의 콘텐츠(본문 내용)을 조회합니다. #### Path parameters - **`id` (required)**: `integer` 이메일 아이디 #### Query parameters - **`abTest`**: `string`, possible values: `"A", "B"` A/B 테스트 이메일에서 조회할 버전(A 또는 B). 생략하면 기본 콘텐츠를 반환한다. #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | ---------------------------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 이메일의 소유자가 아닌 경우 | | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | abTest 값이 잘못된 경우. 'A' 또는 'B'여야 합니다 | | | `400` | `Errors.Editor.NoHTMLExist` | `NoHTMLExist` | 이메일의 콘텐츠가 아직 저장되지 않은 경우 | | ##### 200 이메일 콘텐츠 조회 성공 **Content type:** `text/html` `string` **Example:** ```html hello ``` ##### 400 실패 **Content type:** `application/json` [GetEmailContentErrorResponse](#scalar-schema-getemailcontenterrorresponse) **Example: PermissionDenied** 이메일의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: InvalidRequest** abTest 값이 잘못된 경우. 'A' 또는 'B'여야 합니다 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` **Example: NoHTMLExist** 이메일의 콘텐츠가 아직 저장되지 않은 경우 ```json { "code": "Errors.Editor.NoHTMLExist", "httpStatusCode": 400, "message": "HTML 파일이 존재하지 않습니다." } ``` ### 콘텐츠 수정 - **Method:** `POST` - **Path:** `/emails/{id}/content` - **Operation ID:** `updateEmailContent` - **Tags:** 이메일 - 콘텐츠 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 일반 이메일의 콘텐츠(본문 내용)를 수정합니다. - 작성 중 상태인 일반 이메일만 콘텐츠를 수정할 수 있습니다. 자동 이메일은 지원하지 않습니다. - 요청 본문은 `text/html` 형식이어야 합니다. #### Path parameters - **`id` (required)**: `integer` 이메일 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · text/html** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | ----- | -------------- | -------- | ----- | ------------- | ------ | | `$` | `본문 전송 여부와 별개` | `string` | | 이메일 콘텐츠(HTML) | | **Content type:** `text/html` `string` 이메일 콘텐츠(HTML) **Example: default** ```html hello ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | -------------------------- | ------------- | ------------------------- | ----- | | `400` | `Errors.Email.WrongStatus` | `WrongStatus` | 작성 중 상태가 아니어서 편집할 수 없는 경우 | | ##### 200 이메일 콘텐츠 수정 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [UpdateEmailContentErrorResponse](#scalar-schema-updateemailcontenterrorresponse) **Example: WrongStatus** 작성 중 상태가 아니어서 편집할 수 없는 경우 ```json { "code": "Errors.Email.WrongStatus", "httpStatusCode": 400, "message": "이메일 상태를 확인 하세요." } ``` ### 태그 할당 - **Method:** `POST` - **Path:** `/emails/{id}/tags/assign` - **Operation ID:** `assignEmailTags` - **Tags:** 이메일 - 태그 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 이메일에 태그를 할당합니다. 태그 아이디를 쿼리 파라미터로 전달합니다. #### Path parameters - **`id` (required)**: `integer` 이메일 아이디 #### Query parameters - **`tagIds` (required)**: `string` 할당할 태그 아이디(쉼표로 구분) **Example: default** ```json "1,2" ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | ---------------------------------------------------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 이메일 또는 태그의 소유자가 아닌 경우 | | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | tagIds가 잘못된 형식이거나, 존재하지 않는 태그가 포함되어 요청한 개수와 실제 태그 수가 다른 경우 | | ##### 200 태그 할당 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_6427954453](#scalar-schema-sharederrorresponse-6427954453) **Example: PermissionDenied** 이메일 또는 태그의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: InvalidRequest** tagIds가 잘못된 형식이거나, 존재하지 않는 태그가 포함되어 요청한 개수와 실제 태그 수가 다른 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` ### 태그 해제 - **Method:** `POST` - **Path:** `/emails/{id}/tags/release` - **Operation ID:** `releaseEmailTags` - **Tags:** 이메일 - 태그 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 이메일에 할당된 태그를 해제합니다. #### Path parameters - **`id` (required)**: `integer` 이메일 아이디 #### Query parameters - **`tagIds` (required)**: `string`, pattern: `^\d+(,\d+)*$` 태그 아이디(쉼표로 구분) **Example: default** ```json "1,2" ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 이메일 또는 태그의 소유자가 아닌 경우 | | ##### 200 태그 해제 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) **Example: PermissionDenied** 이메일 또는 태그의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 주소록 목록 조회 - **Method:** `GET` - **Path:** `/lists` - **Operation ID:** `getLists` - **Tags:** 주소록 **요금제 · 요청 제한:** 엔터프라이즈 · 1000회/분 워크스페이스에 생성된 주소록 목록을 조회합니다. #### Query parameters - **`offset`**: `integer`, format: `int`, default: `0` - **`limit`**: `integer`, format: `int`, default: `20` - **`sortOrder`**: `string`, possible values: `"desc", "asc"`, default: `"desc"` 정렬 방향 - desc: 내림차순 - asc: 오름차순 #### Responses ##### 200 주소록 목록 조회 성공 **Content type:** `application/json` [GetListsResponse](#scalar-schema-getlistsresponse) 주소록 목록입니다. 주소록이 없으면 `null` 을 반환합니다. **Example: ListsExist** 주소록이 있는 경우 ```json [ { "id": 1234, "owner": "abcd1234-ab12-cd34-ef56-abcdef123456", "name": "내 주소록", "senderName": "고길동", "companyName": "회사명", "companyContact": "0212341234", "companyAddress": "서울시 중구 동호로", "useSubscriberAutoDelete": true, "canSendToUnsubscribed": false, "useAutoDeletion": true } ] ``` **Example: NoLists** 주소록이 없는 경우(0건) ```json null ``` ### 주소록 생성 - **Method:** `POST` - **Path:** `/lists` - **Operation ID:** `createList` - **Tags:** 주소록 **요금제 · 요청 제한:** 엔터프라이즈 · 1000회/분 새로운 주소록을 생성합니다. - 주소록 생성 시 워크스페이스 소유자의 이메일 주소가 기본 발신자 이메일 주소로 등록됩니다. #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | ------------------------- | ----------------- | --------- | ---------------- | -------------------- | -------------- | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `name` | `필수 (부모 객체 존재 시)` | `string` | | 주소록 이름 | `"주소록 이름"` | | `senderName` | `필수 (부모 객체 존재 시)` | `string` | | 기본 발신자 이름 | `"고길동"` | | `companyName` | `필수 (부모 객체 존재 시)` | `string` | | 회사명 또는 이름 | `"회사명"` | | `companyContact` | `필수 (부모 객체 존재 시)` | `string` | | 전화번호 | `"0212341234"` | | `companyAddress` | `필수 (부모 객체 존재 시)` | `string` | | 주소 | `"서울시 중구 동호로"` | | `useSubscriberAutoDelete` | `선택` | `boolean` | `default: true` | 자동삭제 기능 사용 여부 | `true` | | `canSendToUnsubscribed` | `선택` | `boolean` | `default: false` | 수신거부 구독자 발송 대상 포함 여부 | `false` | **Content type:** `application/json` [CreateListRequest](#scalar-schema-createlistrequest) #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | ---------------------------- | ---------------- | ------------ | --------------------------------------------------------------------------------------------------- | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 필수 값이 누락된 경우 | `{"values":{"message":"name, senderName, companyName, companyContact, companyAddress 값은 필수 입니다."}}` | ##### 200 주소록 생성 성공 **Content type:** `application/json` [CreateListResponse](#scalar-schema-createlistresponse) ##### 400 실패 **Content type:** `application/json` [CreateListErrorResponse](#scalar-schema-createlisterrorresponse) **Example: InvalidRequest** 필수 값이 누락된 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "name, senderName, companyName, companyContact, companyAddress 값은 필수 입니다." } } ``` ### 주소록 삭제 - **Method:** `DELETE` - **Path:** `/lists/{id}` - **Operation ID:** `deleteList` - **Tags:** 주소록 **요금제 · 요청 제한:** 엔터프라이즈 · 1000회/분 주소록을 삭제합니다. #### Path parameters - **`id` (required)**: `integer` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | ------------------------ | ----- | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 주소록 아이디를 숫자로 해석할 수 없는 경우 | | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | ##### 200 주소록 삭제 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_d9bfb03eb3](#scalar-schema-sharederrorresponse-d9bfb03eb3) **Example: InvalidRequest** 주소록 아이디를 숫자로 해석할 수 없는 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 주소록 정보 조회 - **Method:** `GET` - **Path:** `/lists/{id}` - **Operation ID:** `getList` - **Tags:** 주소록 **요금제 · 요청 제한:** 엔터프라이즈 · 1000회/분 주소록의 정보(주소록 이름, 기본 발신자 이메일 주소, 푸터 정보 등)를 조회합니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `404` | `Errors.Data.NoData` | `NoData` | 주소록이 존재하지 않는 경우 | | ##### 200 주소록 정보 조회 성공 **Content type:** `application/json` [GetListResponse](#scalar-schema-getlistresponse) **Example: default** ```json { "id": 1234, "owner": "abcd1234-ab12-cd34-ef56-abcdef123456", "name": "주소록 이름", "senderName": "발신자 이름", "companyName": "회사명", "companyContact": "hello@stibee.com", "companyAddress": "서울시 중구 동호로", "useSubscriberAutoDelete": true, "canSendToUnsubscribed": false } ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ##### 404 찾을 수 없음 **Content type:** `application/json` [GetListNotFoundResponse](#scalar-schema-getlistnotfoundresponse) **Example: NoData** 주소록이 존재하지 않는 경우 ```json { "code": "Errors.Data.NoData", "httpStatusCode": 404, "message": "데이터가 없습니다." } ``` ### 주소록 정보 수정 - **Method:** `PUT` - **Path:** `/lists/{id}` - **Operation ID:** `updateList` - **Tags:** 주소록 **요금제 · 요청 제한:** 엔터프라이즈 · 1000회/분 주소록 정보를 수정합니다. - 변경하고 싶은 필드만 요청 본문에 포함하면 됩니다. - 빈 문자열이 아닌 필드만 수정됩니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | ------------------------- | -------------- | --------- | ----- | -------------------- | ------ | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `name` | `선택` | `string` | | 주소록 이름 | | | `senderName` | `선택` | `string` | | 기본 발신자 이름 | | | `companyName` | `선택` | `string` | | 회사명 또는 이름 | | | `companyContact` | `선택` | `string` | | 전화번호 | | | `companyAddress` | `선택` | `string` | | 주소 | | | `useSubscriberAutoDelete` | `선택` | `boolean` | | 자동삭제 기능 사용 여부 | | | `canSendToUnsubscribed` | `선택` | `boolean` | | 수신거부 구독자 발송 대상 포함 여부 | | **Content type:** `application/json` [UpdateListRequest](#scalar-schema-updatelistrequest) **Example: default** ```json { "name": "주소록 이름", "senderName": "발신자 이름", "companyName": "회사명", "companyContact": "hello@stibee.com", "companyAddress": "서울시 중구 동호로", "useSubscriberAutoDelete": true, "canSendToUnsubscribed": false } ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | ##### 200 주소록 정보 수정 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 주소록 복사 - **Method:** `POST` - **Path:** `/lists/{id}/copy` - **Operation ID:** `copyList` - **Tags:** 주소록 **요금제 · 요청 제한:** 엔터프라이즈 · 1000회/분 주소록을 복사해 새로운 주소록을 생성합니다. #### Path parameters - **`id` (required)**: `integer` 복사할 주소록 아이디 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | ----------------------------------------------- | ----------------------------------- | ---------------------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 주소록 아이디가 잘못된 경우 | | | `400` | `Errors.List.NotUpdatableCanSendToUnsubscribed` | `NotUpdatableCanSendToUnsubscribed` | 이메일의 수신거부 구독자 발송 설정과 충돌하는 경우 | | ##### 200 주소록 복사 성공 **Content type:** `application/json` [CopyListResponse](#scalar-schema-copylistresponse) ##### 400 실패 **Content type:** `application/json` [CopyListErrorResponse](#scalar-schema-copylisterrorresponse) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: InvalidRequest** 주소록 아이디가 잘못된 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` **Example: NotUpdatableCanSendToUnsubscribed** 이메일의 수신거부 구독자 발송 설정과 충돌하는 경우 ```json { "code": "Errors.List.NotUpdatableCanSendToUnsubscribed", "httpStatusCode": 400, "message": "수신거부 구독자 발송이 포함된 예약/자동 이메일이 있어 설정을 변경할 수 없습니다." } ``` ### 구독자 그룹 할당 - **Method:** `POST` - **Path:** `/lists/{id}/groups/{groupId}/assign` - **Operation ID:** `assignGroup` - **Tags:** 주소록 - 구독자 **요금제 · 요청 제한:** 스탠다드 · 프로 · 엔터프라이즈 · 1000회/분 구독자를 그룹에 할당합니다. - 이미 해당 그룹에 할당된 구독자를 다시 할당하면 400 오류(Errors.Data.Duplicated)가 반환됩니다. 할당 전에 그룹 멤버십을 확인하거나, 이 400을 "이미 할당됨"으로 처리하세요. - 주소록에 존재하지 않는 구독자이거나 존재하지 않는 그룹이면 400 오류 응답이 반환됩니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 - **`groupId` (required)**: `integer` 그룹 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | ------------ | ----------------- | -------- | ----------------- | ------- | ------------------------- | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `subscriber` | `필수 (부모 객체 존재 시)` | `string` | `format: "email"` | 구독자 이메일 | `"gildong.go@stibee.com"` | **Content type:** `application/json` [AssignGroupRequest](#scalar-schema-assigngrouprequest) #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | ---------------------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.List.NotExistEmail` | `NotExistEmail` | 주소록에 존재하지 않는 구독자인 경우 | | | `400` | `Errors.List.NoSuchGroup` | `NoSuchGroup` | 존재하지 않는 그룹인 경우 | | | `400` | `Errors.Data.Duplicated` | `Duplicated` | 이미 해당 그룹에 할당된 구독자를 다시 할당한 경우 | | ##### 200 구독자 그룹 할당 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [AssignGroupErrorResponse](#scalar-schema-assigngrouperrorresponse) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: NotExistEmail** 주소록에 존재하지 않는 구독자인 경우 ```json { "code": "Errors.List.NotExistEmail", "httpStatusCode": 400, "message": "존재하지 않는 이메일 주소 입니다." } ``` **Example: NoSuchGroup** 존재하지 않는 그룹인 경우 ```json { "code": "Errors.List.NoSuchGroup", "httpStatusCode": 400, "message": "그룹이 존재하지 않습니다." } ``` **Example: Duplicated** 이미 해당 그룹에 할당된 구독자를 다시 할당한 경우 ```json { "code": "Errors.Data.Duplicated", "httpStatusCode": 400, "message": "중복된 값입니다." } ``` ### 구독자 그룹 해제 - **Method:** `POST` - **Path:** `/lists/{id}/groups/{groupId}/release` - **Operation ID:** `releaseGroup` - **Tags:** 주소록 - 구독자 **요금제 · 요청 제한:** 스탠다드 · 프로 · 엔터프라이즈 · 1000회/분 구독자에게 할당된 그룹을 해제합니다. - 할당되지 않은 구독자이거나 존재하지 않는 그룹에 대해 요청해도 200 응답이 반환됩니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 - **`groupId` (required)**: `integer` 그룹 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | ------------ | ----------------- | -------- | ----------------- | ------- | ------------------------- | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `subscriber` | `필수 (부모 객체 존재 시)` | `string` | `format: "email"` | 구독자 이메일 | `"gildong.go@stibee.com"` | **Content type:** `application/json` [ReleaseGroupRequest](#scalar-schema-releasegrouprequest) #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | ##### 200 그룹 해제 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 구독자 완전 삭제 - **Method:** `DELETE` - **Path:** `/lists/{id}/subscribers` - **Operation ID:** `deleteSubscribers` - **Tags:** 주소록 - 구독자 **요금제 · 요청 제한:** 스탠다드 · 프로 · 엔터프라이즈 · 1000회/분 주소록에서 구독자를 완전히 삭제합니다. 삭제된 구독자는 복구할 수 없습니다. - 구독자를 삭제하지 않고 수신거부하려면 [구독자 수신거부](/스티비-api/tag/주소록---구독자/post/lists/id/subscribers/subscriber/unsubscribe) 요청을 해야합니다. - 한 번에 최대 100명의 구독자를 삭제할 수 있습니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | --------------- | ----------------- | -------- | ----------------- | ------------------------------------------------- | ------ | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `subscribers` | `필수 (부모 객체 존재 시)` | `array` | `maxItems: 100` | 삭제할 구독자 이메일 목록
\* 한번에 최대 요청할 수 있는 개수는 100명
| | | `subscribers[]` | `배열 원소 스키마` | `string` | `format: "email"` | | | **Content type:** `application/json` [DeleteSubscribersRequest](#scalar-schema-deletesubscribersrequest) **Example: default** ```json { "subscribers": [ "gildong.go@stibee.com", "dooly@stibee.com" ] } ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------------------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.Data.LimitExceeded` | `LimitExceeded` | 한 번에 삭제할 수 있는 개수(최대 100명)를 초과한 경우 | | ##### 200 구독자 삭제 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [DeleteSubscribersErrorResponse](#scalar-schema-deletesubscriberserrorresponse) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: LimitExceeded** 한 번에 삭제할 수 있는 개수(최대 100명)를 초과한 경우 ```json { "code": "Errors.Data.LimitExceeded", "httpStatusCode": 400, "message": "요청 제한을 초과하였습니다." } ``` ### 구독자 목록 조회 - **Method:** `GET` - **Path:** `/lists/{id}/subscribers` - **Operation ID:** `getSubscribers` - **Tags:** 주소록 - 구독자 **요금제 · 요청 제한:** 스탠다드 · 프로 · 엔터프라이즈 · 100회/분 주소록의 구독자 목록을 조회합니다. - `statuses` 파라미터로 특정 상태의 구독자만 조회할 수 있습니다. - 한 번에 최대 1,000명의 구독자를 조회할 수 있습니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Query parameters - **`statuses`**: `string` 조회할 구독자 상태(쉼표로 구분). subscribed / unsubscribed / ready / archived 중에서 선택합니다. - 대소문자를 구분하지 않습니다. - 토큰 앞뒤 공백은 허용되지 않습니다. 공백이 포함된 토큰은 무시됩니다. **Example: default** ```json "subscribed,unsubscribed,archived,ready" ``` - **`offset`**: `integer`, default: `0`, minimum: `0` 현재 데이터 조회가 시작되는 위치 - **`limit`**: `integer`, default: `100`, maximum: `1000` 한 번에 가져올 데이터의 최대 개수 (최대 1000) #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | ----------------------------------- | ----- | | `400` | `Errors.Data.LimitExceeded` | `LimitExceeded` | 한 번에 조회할 수 있는 범위(최대 1,000명)를 초과한 경우 | | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | ##### 200 구독자 목록 조회 성공 **Content type:** `application/json` array of [GetSubscribersResponse](#scalar-schema-getsubscribersresponse) **Example: default** ```json [ { "email": "gildong@stibee.com", "status": "subscribed", "fields": { "$ad_agreed": "", "age": "45", "name": "고길동" }, "createdTime": "2024-11-12 17:09:13 +0900 KST", "modifiedTime": "2024-11-17 20:01:11 +0900 KST" } ] ``` ##### 400 실패 **Content type:** `application/json` [GetSubscribersErrorResponse](#scalar-schema-getsubscriberserrorresponse) **Example: LimitExceeded** 한 번에 조회할 수 있는 범위(최대 1,000명)를 초과한 경우 ```json { "code": "Errors.Data.LimitExceeded", "httpStatusCode": 400, "message": "요청 제한을 초과하였습니다." } ``` **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 구독자 추가 - **Method:** `POST` - **Path:** `/lists/{id}/subscribers` - **Operation ID:** `addSubscriber` - **Tags:** 주소록 - 구독자 **요금제 · 요청 제한:** 스탠다드 · 프로 · 엔터프라이즈 · 1000회/분 주소록에 구독자를 추가합니다. - 이메일 주소는 최대 64자까지 입력할 수 있습니다. - `updateEnabled`가 `false`(기본값)이면, 이미 존재하는 구독자를 추가하려고 하면 400 오류 응답이 반환됩니다. - `updateEnabled`가 `true`이면, 이미 존재하는 구독자를 추가하면 기존 정보가 업데이트 되고 201 응답이 반환됩니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | ----------------------------- | ----------------- | --------- | ------------------------------------- | ------------------------------------------------------------------------------ | ------------------------- | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `subscriber` | `필수 (부모 객체 존재 시)` | `object` | | | | | `subscriber.email` | `필수 (부모 객체 존재 시)` | `string` | `format: "email"` | 구독자 이메일 주소 | | | `subscriber.status` | `필수 (부모 객체 존재 시)` | `string` | `enum: ["subscribed","unsubscribed"]` | 구독자 상태
\* subscribed: 구독 중
\* unsubscribed: 수신거부
| | | `subscriber.marketingAllowed` | `선택` | `boolean` | `default: false` | 광고성 정보 수신동의 여부 | | | `subscriber.fields` | `선택` | `object` | | 주소록에 생성된 사용자 정의 필드별 값 (주소록에 생성되어있는 필드만 값을 입력할 수 있음) | `{"name":"고길동","age":45}` | | `updateEnabled` | `선택` | `boolean` | `default: false` | 구독자가 이미 존재할 경우 fields 값들의 업데이트 여부. false이면 업데이트하지 않음. true이면 새로 요청한 값으로 업데이트함. | | **Content type:** `application/json` [AddSubscriberRequest](#scalar-schema-addsubscriberrequest) **Example: default** ```json { "subscriber": { "email": "gildong.go@stibee.com", "status": "subscribed", "marketingAllowed": true, "fields": { "name": "고길동" } }, "updateEnabled": true } ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------------- | -------------------------------------------------- | -------------------------------- | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 요청 본문의 형식이 잘못된 경우 | | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.List.NoEmail` | `NoEmail` | 이메일 주소가 비어 있는 경우 | | | `400` | `Errors.List.InvalidEmail` | `InvalidEmail` | 이메일 주소 형식이 잘못된 경우 | | | `400` | `Errors.List.InvalidSubscriberVar` | `InvalidSubscriberVar` | 주소록에 없는 사용자 정의 필드를 사용한 경우 | `{"values":{"field":"address"}}` | | `400` | `Errors.List.InvalidSubscriberStatus` | `InvalidSubscriberStatus` | 구독자 상태 값이 잘못된 경우 | | | `400` | `Errors.List.AlreadyExistEmail` | `AlreadyExistEmail` | \`updateEnabled\`가 \`false\`인데 주소록에 이미 추가된 구독자인 경우 | | ##### 200 구독자 추가 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 201 구독자 업데이트 성공 (\`updateEnabled\`가 \`true\`이고 이미 존재하는 구독자를 추가했을 때) **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [AddSubscriberErrorResponse](#scalar-schema-addsubscribererrorresponse) **Example: InvalidRequest** 요청 본문의 형식이 잘못된 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: NoEmail** 이메일 주소가 비어 있는 경우 ```json { "code": "Errors.List.NoEmail", "httpStatusCode": 400, "message": "이메일 주소를 입력하세요." } ``` **Example: InvalidEmail** 이메일 주소 형식이 잘못된 경우 ```json { "code": "Errors.List.InvalidEmail", "httpStatusCode": 400, "message": "잘못된 이메일 주소입니다." } ``` **Example: InvalidSubscriberVar** 주소록에 없는 사용자 정의 필드를 사용한 경우 ```json { "code": "Errors.List.InvalidSubscriberVar", "httpStatusCode": 400, "message": "사용할 수 없는 사용자정의필드 입니다.", "values": { "field": "address" } } ``` **Example: InvalidSubscriberStatus** 구독자 상태 값이 잘못된 경우 ```json { "code": "Errors.List.InvalidSubscriberStatus", "httpStatusCode": 400, "message": "잘못된 구독자 상태 입니다." } ``` **Example: AlreadyExistEmail** `updateEnabled`가 `false`인데 주소록에 이미 추가된 구독자인 경우 ```json { "code": "Errors.List.AlreadyExistEmail", "httpStatusCode": 400, "message": "이미 존재하는 이메일 입니다." } ``` ### 구독자 정보 수정 - **Method:** `PUT` - **Path:** `/lists/{id}/subscribers/{subscriber}` - **Operation ID:** `updateSubscriber` - **Tags:** 주소록 - 구독자 **요금제 · 요청 제한:** 스탠다드 · 프로 · 엔터프라이즈 · 1000회/분 구독자의 사용자 정의 필드 값을 수정합니다. - 구독자의 상태(status)는 변경되지 않습니다. - 주소록에 존재하지 않는 구독자에 대한 요청은 400 오류 응답이 반환됩니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 - **`subscriber` (required)**: `string` 구독자 이메일 주소 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | -------- | ----------------- | -------- | ----- | --------------------------------------------------- | ---------------- | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `fields` | `필수 (부모 객체 존재 시)` | `object` | | 주소록에 생성된 사용자 정의 필드별 값 (주소록에 생성되어있는 필드만 값을 입력할 수 있음) | `{"name":"고길동"}` | **Content type:** `application/json` [UpdateSubscriberRequest](#scalar-schema-updatesubscriberrequest) #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | -------------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.List.NotExistEmail` | `NotExistEmail` | 주소록에 존재하지 않는 구독자인 경우 | | ##### 200 구독자 정보 수정 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_b33e216723](#scalar-schema-sharederrorresponse-b33e216723) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: NotExistEmail** 주소록에 존재하지 않는 구독자인 경우 ```json { "code": "Errors.List.NotExistEmail", "httpStatusCode": 400, "message": "존재하지 않는 이메일 주소 입니다." } ``` ### 구독자 수신거부 - **Method:** `POST` - **Path:** `/lists/{id}/subscribers/{subscriber}/unsubscribe` - **Operation ID:** `unsubscribeSubscriber` - **Tags:** 주소록 - 구독자 **요금제 · 요청 제한:** 스탠다드 · 프로 · 엔터프라이즈 · 1000회/분 구독자를 수신거부합니다. - 구독자가 삭제되지 않고 상태만 수신거부(unsubscribed)로 변경됩니다. - 구독자를 삭제하려면 [구독자 완전 삭제](/스티비-api/tag/주소록---구독자/delete/lists/id/subscribers) 요청을 해야합니다. - 이미 수신거부 상태인 구독자에 대한 요청은 200 응답이 반환됩니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 - **`subscriber` (required)**: `string`, format: `email` 구독자 이메일 주소 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | -------------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.List.NotExistEmail` | `NotExistEmail` | 주소록에 존재하지 않는 구독자인 경우 | | ##### 200 구독자 수신거부 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_b33e216723](#scalar-schema-sharederrorresponse-b33e216723) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: NotExistEmail** 주소록에 존재하지 않는 구독자인 경우 ```json { "code": "Errors.List.NotExistEmail", "httpStatusCode": 400, "message": "존재하지 않는 이메일 주소 입니다." } ``` ### 구독자 대량 추가 - **Method:** `POST` - **Path:** `/lists/{id}/subscribers/batch` - **Operation ID:** `batchAddSubscribers` - **Tags:** 주소록 - 구독자 **요금제 · 요청 제한:** 스탠다드 · 프로 · 엔터프라이즈 · 10회/분 주소록에 여러 구독자를 한 번에 추가합니다. - 한 번에 최대 1,000명의 구독자를 추가할 수 있습니다. - 요청 본문은 최대 10MB까지 허용됩니다. - 일부 구독자는 성공하고 일부는 실패할 수 있습니다. 응답에서 성공, 실패한 구독자 목록을 확인할 수 있습니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | -------------------------------- | ----------------- | --------- | ------------------------------------- | ------------------------------------------------------------------------------ | ------------------------- | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `subscribers` | `필수 (부모 객체 존재 시)` | `array` | `maxItems: 1000` | 추가할 구독자 목록 (최대 1,000명) | | | `subscribers[]` | `배열 원소 스키마` | `object` | | | | | `subscribers[].email` | `필수 (부모 객체 존재 시)` | `string` | `format: "email"` | 구독자 이메일 주소 | `"gildong.go@stibee.com"` | | `subscribers[].status` | `필수 (부모 객체 존재 시)` | `string` | `enum: ["subscribed","unsubscribed"]` | 구독자 상태
\* subscribed: 구독 중
\* unsubscribed: 수신거부
| | | `subscribers[].fields` | `선택` | `object` | | 주소록에 생성된 사용자 정의 필드별 값 (주소록에 생성되어있는 필드만 값을 입력할 수 있음) | `{"name":"고길동"}` | | `subscribers[].marketingAllowed` | `선택` | `boolean` | `default: false` | 광고성 정보 수신동의 여부 | | | `updateEnabled` | `선택` | `boolean` | `default: false` | 구독자가 이미 존재할 경우 fields 값들의 업데이트 여부. false이면 업데이트하지 않음. true이면 새로 요청한 값으로 업데이트함. | | **Content type:** `application/json` [BatchSubscriberRequest](#scalar-schema-batchsubscriberrequest) #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | ----------------------------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 요청 본문의 형식이 잘못된 경우 | | | `400` | `Errors.Data.TooLongData` | `TooLongData` | 요청 본문이 10MB를 초과한 경우 | | | `400` | `Errors.Data.LimitExceeded` | `LimitExceeded` | 한 번에 추가할 수 있는 개수(최대 1,000명)를 초과한 경우 | | ##### 200 구독자 대량 추가 성공 **Content type:** `application/json` [BatchSubscriberResponse](#scalar-schema-batchsubscriberresponse) ##### 400 실패 **Content type:** `application/json` [BatchAddSubscribersErrorResponse](#scalar-schema-batchaddsubscriberserrorresponse) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: InvalidRequest** 요청 본문의 형식이 잘못된 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` **Example: TooLongData** 요청 본문이 10MB를 초과한 경우 ```json { "code": "Errors.Data.TooLongData", "httpStatusCode": 400, "message": "데이터 길이가 너무 깁니다." } ``` **Example: LimitExceeded** 한 번에 추가할 수 있는 개수(최대 1,000명)를 초과한 경우 ```json { "code": "Errors.Data.LimitExceeded", "httpStatusCode": 400, "message": "요청 제한을 초과하였습니다." } ``` ### 구독자 수 조회 - **Method:** `GET` - **Path:** `/lists/{id}/subscribers/count` - **Operation ID:** `getSubscriberCount` - **Tags:** 주소록 - 구독자 **요금제 · 요청 제한:** 스탠다드 · 프로 · 엔터프라이즈 · 1000회/분 주소록의 구독자 수를 조회합니다. - `statuses` 파라미터로 특정 상태의 구독자 수만 조회할 수 있습니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Query parameters - **`statuses`**: `string` 조회할 구독자 상태(쉼표로 구분). subscribed / unsubscribed / ready / archived 중에서 선택합니다. - 대소문자를 구분하지 않습니다. - 토큰 앞뒤 공백은 허용되지 않습니다. 공백이 포함된 토큰은 무시됩니다. **Example: default** ```json "subscribed,unsubscribed,archived,ready" ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | ##### 200 구독자 수 조회 성공 **Content type:** `application/json` [GetSubscriberCountResponse](#scalar-schema-getsubscribercountresponse) ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 구독자 추가 - 구독 확인 이메일 발송 - **Method:** `POST` - **Path:** `/lists/{id}/subscribers/double-optin` - **Operation ID:** `sendDoubleOptin` - **Tags:** 주소록 - 구독자 **요금제 · 요청 제한:** 스탠다드 · 프로 · 엔터프라이즈 · 1000회/분 구독 확인 과정을 거쳐 구독자를 추가합니다. - 구독자가 '구독 대기' 상태로 주소록에 추가되고 구독 확인 이메일이 발송됩니다. - 구독자가 구독 확인을 하면 주소록에서 '구독 중' 상태로 변경됩니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | ------------------- | ----------------- | -------- | ----------------- | --------------------------------------------------- | ------------------------- | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `subscriber` | `필수 (부모 객체 존재 시)` | `object` | | | | | `subscriber.email` | `필수 (부모 객체 존재 시)` | `string` | `format: "email"` | 구독자 이메일 주소 | | | `subscriber.fields` | `선택` | `object` | | 주소록에 생성된 사용자 정의 필드별 값 (주소록에 생성되어있는 필드만 값을 입력할 수 있음) | `{"name":"고길동","age":45}` | **Content type:** `application/json` [SendDoubleOptinRequest](#scalar-schema-senddoubleoptinrequest) **Example: default** ```json { "subscriber": { "email": "gildong.go@stibee.com", "fields": { "name": "고길동" } } } ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------------- | -------------------------------------------------- | -------------------------------- | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 요청 본문의 형식이 잘못된 경우 | | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.List.NoEmail` | `NoEmail` | 이메일 주소가 비어 있는 경우 | | | `400` | `Errors.List.InvalidEmail` | `InvalidEmail` | 이메일 주소 형식이 잘못된 경우 | | | `400` | `Errors.List.InvalidSubscriberVar` | `InvalidSubscriberVar` | 주소록에 없는 사용자 정의 필드를 사용한 경우 | `{"values":{"field":"address"}}` | | `400` | `Errors.List.InvalidSubscriberStatus` | `InvalidSubscriberStatus` | 구독자 상태 값이 잘못된 경우 | | | `400` | `Errors.List.AlreadyExistEmail` | `AlreadyExistEmail` | \`updateEnabled\`가 \`false\`인데 주소록에 이미 추가된 구독자인 경우 | | | `400` | `Errors.List.NotExistEmail` | `NotExistEmail` | 복제 지연으로 방금 추가한 구독자를 아직 조회할 수 없는 경우 | | ##### 200 구독 확인 이메일 발송 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SendDoubleOptinErrorResponse](#scalar-schema-senddoubleoptinerrorresponse) **Example: InvalidRequest** 요청 본문의 형식이 잘못된 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: NoEmail** 이메일 주소가 비어 있는 경우 ```json { "code": "Errors.List.NoEmail", "httpStatusCode": 400, "message": "이메일 주소를 입력하세요." } ``` **Example: InvalidEmail** 이메일 주소 형식이 잘못된 경우 ```json { "code": "Errors.List.InvalidEmail", "httpStatusCode": 400, "message": "잘못된 이메일 주소입니다." } ``` **Example: InvalidSubscriberVar** 주소록에 없는 사용자 정의 필드를 사용한 경우 ```json { "code": "Errors.List.InvalidSubscriberVar", "httpStatusCode": 400, "message": "사용할 수 없는 사용자정의필드 입니다.", "values": { "field": "address" } } ``` **Example: InvalidSubscriberStatus** 구독자 상태 값이 잘못된 경우 ```json { "code": "Errors.List.InvalidSubscriberStatus", "httpStatusCode": 400, "message": "잘못된 구독자 상태 입니다." } ``` **Example: AlreadyExistEmail** `updateEnabled`가 `false`인데 주소록에 이미 추가된 구독자인 경우 ```json { "code": "Errors.List.AlreadyExistEmail", "httpStatusCode": 400, "message": "이미 존재하는 이메일 입니다." } ``` **Example: NotExistEmail** 복제 지연으로 방금 추가한 구독자를 아직 조회할 수 없는 경우 ```json { "code": "Errors.List.NotExistEmail", "httpStatusCode": 400, "message": "존재하지 않는 이메일 주소 입니다." } ``` ### 구독자 성과 조회 - **Method:** `POST` - **Path:** `/lists/{id}/subscribers/stats/query` - **Operation ID:** `querySubscriberStats` - **Tags:** 주소록 - 구독자 **요금제 · 요청 제한:** 스탠다드 · 프로 · 엔터프라이즈 · 100회/분 구독자 한 명이 지정한 이메일들에서 보인 활동을 합산합니다. - 대상 이메일은 `emailIds`로 지정하며, `GET /emails`로 먼저 찾을 수 있습니다. - 모든 값은 로그에 기록된 활동 횟수입니다. 같은 구독자가 한 이메일을 여러 번 열면 그 횟수만큼 `openCount`에 더해집니다. 자동메일처럼 같은 구독자에게 반복 발송되는 경우에는 `successCount`도 1보다 클 수 있습니다. - `emailCount`만 성격이 다릅니다. 활동 횟수가 아니라 실제로 집계한 이메일 수이며, 발송 기록이 없는 이메일은 제외됩니다. - `bounceCount`는 소프트바운스와 하드바운스를 합한 값입니다. - 이메일 단위 오픈율(`GET /emails/stats`)은 구독자 유니크 기준이라 계산 방식이 다릅니다. - 주소록에 없는 구독자를 지정해도 오류가 아닙니다. 활동 횟수가 모두 0인 응답이 반환됩니다. (`emailCount`는 집계를 시도한 이메일 수이므로 0이 아닙니다.) #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | ------------ | ----------------- | --------- | ----- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------- | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `subscriber` | `필수 (부모 객체 존재 시)` | `string` | | 구독자 이메일 주소. 한 번에 한 명만 지정할 수 있습니다.

- 앞뒤 공백은 무시됩니다.
- 주소록에 없는 구독자를 지정해도 오류가 아닙니다. 활동 횟수가 모두 0인 응답이 반환됩니다. (\`emailCount\`는 집계를 시도한 이메일 수이므로 0이 아닙니다.)
| `"gildong.go@stibee.com"` | | `emailIds` | `필수 (부모 객체 존재 시)` | `array` | | 집계할 이메일 아이디 목록.

- 한 번에 최대 30개까지 지정할 수 있습니다.
- 같은 아이디를 여러 번 넣어도 한 번만 집계합니다.
- 이 주소록에 속하지 않은 이메일 아이디가 하나라도 있으면 요청 전체가 거절됩니다.
| `[1024,1025]` | | `emailIds[]` | `배열 원소 스키마` | `integer` | | | | **Content type:** `application/json` [QuerySubscriberStatsRequest](#scalar-schema-querysubscriberstatsrequest) **Example: default** ```json { "subscriber": "gildong.go@stibee.com", "emailIds": [ 1024, 1025 ] } ``` #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------- | ---------------------------- | ---------------------------------------------------------------------- | | `400` | `Errors.Data.MissingRequiredField` | `MissingSubscriber` | subscriber를 지정하지 않은 경우 | `{"values":{"message":"subscriber로 구독자 한 명을 지정해주세요."}}` | | `400` | `Errors.Data.MissingRequiredField` | `MissingEmailIds` | emailIds를 지정하지 않은 경우 | `{"values":{"message":"emailIds로 대상 메일을 하나 이상 지정해주세요."}}` | | `400` | `Errors.Data.InvalidRequest` | `NotInList` | 이 주소록에 속하지 않은 이메일 아이디가 있는 경우 | `{"values":{"emailIds":[1099],"message":"이 주소록에 없는 메일 ID가 있습니다."}}` | | `400` | `Errors.Data.LimitExceeded` | `TooManyEmailIds` | emailIds를 31개 이상 지정한 경우 | `{"values":{"message":"한 번에 최대 30통까지 집계합니다. 메일을 30통 이하로 나눠 요청해주세요."}}` | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | ##### 200 구독자 성과 조회 성공 **Content type:** `application/json` [GetSubscriberStatsResponse](#scalar-schema-getsubscriberstatsresponse) **Example: default** ```json { "subscriber": "gildong.go@stibee.com", "emailCount": 12, "successCount": 12, "openCount": 7, "clickCount": 3, "unsubscribeCount": 0, "bounceCount": 1 } ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_d07945da9c](#scalar-schema-sharederrorresponse-d07945da9c) **Example: MissingSubscriber** subscriber를 지정하지 않은 경우 ```json { "code": "Errors.Data.MissingRequiredField", "httpStatusCode": 400, "message": "필수 항목이 누락되었습니다.", "values": { "message": "subscriber로 구독자 한 명을 지정해주세요." } } ``` **Example: MissingEmailIds** emailIds를 지정하지 않은 경우 ```json { "code": "Errors.Data.MissingRequiredField", "httpStatusCode": 400, "message": "필수 항목이 누락되었습니다.", "values": { "message": "emailIds로 대상 메일을 하나 이상 지정해주세요." } } ``` **Example: NotInList** 이 주소록에 속하지 않은 이메일 아이디가 있는 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "emailIds": [ 1099 ], "message": "이 주소록에 없는 메일 ID가 있습니다." } } ``` **Example: TooManyEmailIds** emailIds를 31개 이상 지정한 경우 ```json { "code": "Errors.Data.LimitExceeded", "httpStatusCode": 400, "message": "요청 제한을 초과하였습니다.", "values": { "message": "한 번에 최대 30통까지 집계합니다. 메일을 30통 이하로 나눠 요청해주세요." } } ``` **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 그룹 목록 조회 - **Method:** `GET` - **Path:** `/lists/{id}/groups` - **Operation ID:** `getGroups` - **Tags:** 주소록 - 그룹 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 주소록에 생성된 그룹 목록을 조회합니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Query parameters - **`offset`**: `integer`, default: `0`, minimum: `0` 현재 데이터 조회가 시작되는 위치 - **`limit`**: `integer`, default: `20`, minimum: `1` 한 번에 가져올 데이터의 최대 개수 - **`sortBy`**: `string`, possible values: `"id", "name"`, default: `"id"` 정렬 기준 - id: 그룹 아이디 - name: 그룹 이름 - **`sortOrder`**: `string`, possible values: `"desc", "asc"`, default: `"desc"` 정렬 방향 - desc: 내림차순 - asc: 오름차순 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | ##### 200 그룹 목록 조회 성공 **Content type:** `application/json` [GetGroupResponse](#scalar-schema-getgroupresponse) ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 그룹 생성 - **Method:** `POST` - **Path:** `/lists/{id}/groups` - **Operation ID:** `createGroup` - **Tags:** 주소록 - 그룹 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 주소록에 새로운 그룹을 생성합니다. - 같은 이름의 그룹이 이미 존재하면 400 오류가 반환됩니다. - 요금제에 따라 생성 가능한 그룹 수에 제한이 있습니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | ------ | ----------------- | -------- | ----- | ----- | --------- | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `name` | `필수 (부모 객체 존재 시)` | `string` | | 그룹 이름 | `"그룹 이름"` | **Content type:** `application/json` [CreateGroupRequest](#scalar-schema-creategrouprequest) #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------- | --------------------------------------------------------------- | ---------------------------- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 그룹 이름이 비어 있는 경우 | | | `400` | `Errors.List.AlreadyExistGroup` | `AlreadyExistGroup` | 같은 이름의 그룹이 이미 있는 경우 | | | `400` | `Errors.List.TooManyGroups` | `TooManyGroups` | 그룹 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 \`values.maxCount\`로 전달됩니다. | `{"values":{"maxCount":30}}` | ##### 200 그룹 생성 성공 **Content type:** `application/json` [CreateGroupResponse](#scalar-schema-creategroupresponse) ##### 400 실패 **Content type:** `application/json` [CreateGroupErrorResponse](#scalar-schema-creategrouperrorresponse) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: InvalidRequest** 그룹 이름이 비어 있는 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` **Example: AlreadyExistGroup** 같은 이름의 그룹이 이미 있는 경우 ```json { "code": "Errors.List.AlreadyExistGroup", "httpStatusCode": 400, "message": "그룹이 이미 존재합니다." } ``` **Example: TooManyGroups** 그룹 수 제한을 초과한 경우. 최대 개수는 요금제에 따라 다르며 `values.maxCount`로 전달됩니다. ```json { "code": "Errors.List.TooManyGroups", "httpStatusCode": 400, "message": "그룹은 최대 {maxCount}개 까지만 만들 수 있습니다.", "values": { "maxCount": 30 } } ``` ### 그룹 삭제 - **Method:** `DELETE` - **Path:** `/lists/{id}/groups/{groupId}` - **Operation ID:** `deleteGroup` - **Tags:** 주소록 - 그룹 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 그룹을 삭제합니다. - 그룹에 할당된 구독자는 삭제되지 않고, 삭제하는 그룹에서만 할당이 해제됩니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 - **`groupId` (required)**: `integer` 그룹 아이디 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | ##### 200 그룹 삭제 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_3a6c2c2fa6](#scalar-schema-sharederrorresponse-3a6c2c2fa6) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 그룹 정보 수정 - **Method:** `PUT` - **Path:** `/lists/{id}/groups/{groupId}` - **Operation ID:** `updateGroup` - **Tags:** 주소록 - 그룹 **요금제 · 요청 제한:** 프로 · 엔터프라이즈 · 1000회/분 그룹의 이름을 수정합니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 - **`groupId` (required)**: `integer` 그룹 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | ------ | ----------------- | -------- | ----- | ----- | --------- | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `name` | `필수 (부모 객체 존재 시)` | `string` | | 그룹 이름 | `"그룹 이름"` | **Content type:** `application/json` [UpdateGroupRequest](#scalar-schema-updategrouprequest) #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | --------------- | ----- | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 그룹 이름이 비어 있는 경우 | | ##### 200 그룹 정보 수정 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_6427954453](#scalar-schema-sharederrorresponse-6427954453) **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: InvalidRequest** 그룹 이름이 비어 있는 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` ### 발신자 이메일 주소 목록 조회 - **Method:** `GET` - **Path:** `/lists/{id}/senders` - **Operation ID:** `getListSenders` - **Tags:** 주소록 - 발신자 이메일 주소 **요금제 · 요청 제한:** 엔터프라이즈 · 1000회/분 주소록에 등록된 발신자 이메일 주소를 조회합니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ------------------ | ------------------------ | ----- | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 주소록 아이디를 숫자로 해석할 수 없는 경우 | | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | ##### 200 발신자 이메일 주소 목록 조회 성공 **Content type:** `application/json` array of [GetListSenderResponse](#scalar-schema-getlistsenderresponse) **Example: default** ```json [ { "email": "gildong.go@stibee.com", "authorized": false } ] ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_d9bfb03eb3](#scalar-schema-sharederrorresponse-d9bfb03eb3) **Example: InvalidRequest** 주소록 아이디를 숫자로 해석할 수 없는 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 발신자 이메일 주소 추가 - **Method:** `POST` - **Path:** `/lists/{id}/senders` - **Operation ID:** `addListSender` - **Tags:** 주소록 - 발신자 이메일 주소 **요금제 · 요청 제한:** 엔터프라이즈 · 1000회/분 주소록에 발신자 이메일 주소를 추가합니다. - 인증 이메일이 발송됩니다. 인증을 하면 주소록에 발신자 이메일 주소가 추가됩니다. - 워크스페이스의 다른 주소록에서 이미 인증한 이메일 주소는 인증 이메일이 발송되지 않고 바로 추가됩니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 #### Request body **본문 전송 필수 (requestBody.required):** true 필드의 필수 여부는 그 필드를 담는 부모 객체가 존재할 때 적용됩니다. 배열 원소와 조합 스키마의 분기는 별도로 표시합니다. **요청 필드 · application/json** | 필드 경로 | 필수 여부 | 타입 | 제약 조건 | 설명 | 명시된 예시 | | ------- | ----------------- | -------- | ----------------- | ---------- | ------------------------- | | `$` | `본문 전송 여부와 별개` | `object` | | | | | `email` | `필수 (부모 객체 존재 시)` | `string` | `format: "email"` | 발신자 이메일 주소 | `"gildong.go@stibee.com"` | **Content type:** `application/json` [AddSenderRequest](#scalar-schema-addsenderrequest) #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | -------------------------- | ---------------------------------------------------- | ----- | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 요청 본문이 잘못되었거나 이메일 주소가 비어 있는 경우 | | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.List.NotPermittedSenderDomain` | `NotPermittedSenderDomain` | 발신자 이메일 주소로 사용할 수 없는 도메인인 경우(gmail.com, naver.com 등) | | ##### 200 발신자 이메일 주소 추가 성공 **Content type:** `application/json` [AddSenderResponse](#scalar-schema-addsenderresponse) ##### 400 실패 **Content type:** `application/json` [AddListSenderErrorResponse](#scalar-schema-addlistsendererrorresponse) **Example: InvalidRequest** 요청 본문이 잘못되었거나 이메일 주소가 비어 있는 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: NotPermittedSenderDomain** 발신자 이메일 주소로 사용할 수 없는 도메인인 경우(gmail.com, naver.com 등) ```json { "code": "Errors.List.NotPermittedSenderDomain", "httpStatusCode": 400, "message": "허용되지 않는 발신자 도메인 입니다." } ``` ### 발신자 이메일 주소 삭제 - **Method:** `DELETE` - **Path:** `/lists/{id}/senders/{email}` - **Operation ID:** `deleteListSender` - **Tags:** 주소록 - 발신자 이메일 주소 **요금제 · 요청 제한:** 엔터프라이즈 · 1000회/분 주소록에 등록된 발신자 이메일 주소를 삭제합니다. - 기본 발신자 이메일 주소는 삭제할 수 없습니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 - **`email` (required)**: `string`, format: `email` 발신자 이메일 주소 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | ----------------------------- | ------------------------ | ---------------------------------------------- | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestDefaultSender` | 기본 발신자 이메일 주소를 삭제하려는 경우 | `{"values":{"message":"기본 발신자는 삭제할 수 없습니다."}}` | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequestInvalidId` | 주소록 아이디를 숫자로 해석할 수 없는 경우 | | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | ##### 200 발신자 이메일 주소 삭제 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [SharedErrorResponse_d9bfb03eb3](#scalar-schema-sharederrorresponse-d9bfb03eb3) **Example: InvalidRequestDefaultSender** 기본 발신자 이메일 주소를 삭제하려는 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다.", "values": { "message": "기본 발신자는 삭제할 수 없습니다." } } ``` **Example: InvalidRequestInvalidId** 주소록 아이디를 숫자로 해석할 수 없는 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` ### 발신자 이메일 주소 인증 이메일 발송 - **Method:** `POST` - **Path:** `/lists/{id}/senders/{email}/verify` - **Operation ID:** `verifyListSender` - **Tags:** 주소록 - 발신자 이메일 주소 **요금제 · 요청 제한:** 엔터프라이즈 · 1000회/분 주소록에 이미 추가된 발신자 이메일 주소에 대해 인증 이메일을 다시 발송합니다. #### Path parameters - **`id` (required)**: `integer` 주소록 아이디 - **`email` (required)**: `string`, format: `email` 발신자 이메일 주소 #### Responses **명시된 오류 코드와 조건** | HTTP | 오류 코드 | 예시 이름 | 원본 조건 | 추가 필드 | | ----- | --------------------------------------- | -------------------------- | ---------------------------------------------------- | ----- | | `400` | `Errors.Data.InvalidRequest` | `InvalidRequest` | 주소록 아이디를 숫자로 해석할 수 없는 경우 | | | `400` | `Errors.Authorization.PermissionDenied` | `PermissionDenied` | 주소록의 소유자가 아닌 경우 | | | `400` | `Errors.List.NotExistEmail` | `NotExistEmail` | 주소록에 추가되어 있지 않은 발신자 이메일 주소인 경우 | | | `400` | `Errors.List.NotPermittedSenderDomain` | `NotPermittedSenderDomain` | 발신자 이메일 주소로 사용할 수 없는 도메인인 경우(gmail.com, naver.com 등) | | ##### 200 발신자 이메일 주소 인증 이메일 발송 성공 **Content type:** `text/plain` `string` **Example:** ```text ok ``` ##### 400 실패 **Content type:** `application/json` [VerifyListSenderErrorResponse](#scalar-schema-verifylistsendererrorresponse) **Example: InvalidRequest** 주소록 아이디를 숫자로 해석할 수 없는 경우 ```json { "code": "Errors.Data.InvalidRequest", "httpStatusCode": 400, "message": "잘못된 요청입니다." } ``` **Example: PermissionDenied** 주소록의 소유자가 아닌 경우 ```json { "code": "Errors.Authorization.PermissionDenied", "httpStatusCode": 400, "message": "허용되지 않은 요청입니다." } ``` **Example: NotExistEmail** 주소록에 추가되어 있지 않은 발신자 이메일 주소인 경우 ```json { "code": "Errors.List.NotExistEmail", "httpStatusCode": 400, "message": "존재하지 않는 이메일 주소 입니다." } ``` **Example: NotPermittedSenderDomain** 발신자 이메일 주소로 사용할 수 없는 도메인인 경우(gmail.com, naver.com 등) ```json { "code": "Errors.List.NotPermittedSenderDomain", "httpStatusCode": 400, "message": "허용되지 않는 발신자 도메인 입니다." } ``` ## Schemas 같은 내용의 오류 스키마만 공통 정의로 묶었습니다. 아래 원본 이름은 원본 명세에 그대로 남습니다. | 원본 스키마 | 문서 공통 정의 | | ------------------------------------ | --------------------------------------------------------------------------------- | | `GetEmailStatsErrorResponse` | [`SharedErrorResponse_d07945da9c`](#scalar-schema-sharederrorresponse-d07945da9c) | | `GetEmailErrorResponse` | [`SharedErrorResponse_3a6c2c2fa6`](#scalar-schema-sharederrorresponse-3a6c2c2fa6) | | `DeleteEmailErrorResponse` | [`SharedErrorResponse_3a6c2c2fa6`](#scalar-schema-sharederrorresponse-3a6c2c2fa6) | | `CopyEmailErrorResponse` | [`SharedErrorResponse_3a6c2c2fa6`](#scalar-schema-sharederrorresponse-3a6c2c2fa6) | | `AssignEmailTagsErrorResponse` | [`SharedErrorResponse_6427954453`](#scalar-schema-sharederrorresponse-6427954453) | | `ReleaseEmailTagsErrorResponse` | [`SharedErrorResponse_3a6c2c2fa6`](#scalar-schema-sharederrorresponse-3a6c2c2fa6) | | `CancelReserveEmailErrorResponse` | [`SharedErrorResponse_3a6c2c2fa6`](#scalar-schema-sharederrorresponse-3a6c2c2fa6) | | `GetListErrorResponse` | [`SharedErrorResponse_3a6c2c2fa6`](#scalar-schema-sharederrorresponse-3a6c2c2fa6) | | `UpdateListErrorResponse` | [`SharedErrorResponse_3a6c2c2fa6`](#scalar-schema-sharederrorresponse-3a6c2c2fa6) | | `DeleteListErrorResponse` | [`SharedErrorResponse_d9bfb03eb3`](#scalar-schema-sharederrorresponse-d9bfb03eb3) | | `GetListSendersErrorResponse` | [`SharedErrorResponse_d9bfb03eb3`](#scalar-schema-sharederrorresponse-d9bfb03eb3) | | `GetSubscriberCountErrorResponse` | [`SharedErrorResponse_3a6c2c2fa6`](#scalar-schema-sharederrorresponse-3a6c2c2fa6) | | `UpdateSubscriberErrorResponse` | [`SharedErrorResponse_b33e216723`](#scalar-schema-sharederrorresponse-b33e216723) | | `GetSubscriberStatsErrorResponse` | [`SharedErrorResponse_d07945da9c`](#scalar-schema-sharederrorresponse-d07945da9c) | | `UnsubscribeSubscriberErrorResponse` | [`SharedErrorResponse_b33e216723`](#scalar-schema-sharederrorresponse-b33e216723) | | `ReleaseGroupErrorResponse` | [`SharedErrorResponse_3a6c2c2fa6`](#scalar-schema-sharederrorresponse-3a6c2c2fa6) | | `DeleteListSenderErrorResponse` | [`SharedErrorResponse_d9bfb03eb3`](#scalar-schema-sharederrorresponse-d9bfb03eb3) | | `GetGroupsErrorResponse` | [`SharedErrorResponse_3a6c2c2fa6`](#scalar-schema-sharederrorresponse-3a6c2c2fa6) | | `UpdateGroupErrorResponse` | [`SharedErrorResponse_6427954453`](#scalar-schema-sharederrorresponse-6427954453) | | `DeleteGroupErrorResponse` | [`SharedErrorResponse_3a6c2c2fa6`](#scalar-schema-sharederrorresponse-3a6c2c2fa6) | ### CreateListRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | --------------------------- | -------------- | | `$.name` | `"주소록 이름"` | | `$.senderName` | `"고길동"` | | `$.companyName` | `"회사명"` | | `$.companyContact` | `"0212341234"` | | `$.companyAddress` | `"서울시 중구 동호로"` | | `$.useSubscriberAutoDelete` | `true` | | `$.canSendToUnsubscribed` | `false` | **Type:** `object` - **`companyAddress` (required)**: `string` 주소 - **`companyContact` (required)**: `string` 전화번호 - **`companyName` (required)**: `string` 회사명 또는 이름 - **`name` (required)**: `string` 주소록 이름 - **`senderName` (required)**: `string` 기본 발신자 이름 - **`canSendToUnsubscribed`**: `boolean`, default: `false` 수신거부 구독자 발송 대상 포함 여부 - **`useSubscriberAutoDelete`**: `boolean`, default: `true` 자동삭제 기능 사용 여부 ### CreateListResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------ | ------ | | `$.id` | `1234` | **Type:** `object` - **`id`**: `integer` 주소록 아이디 ### CopyListResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------ | ------ | | `$.id` | `1234` | **Type:** `object` - **`id`**: `integer` 복사된 주소록 아이디 ### GetListsResponse **Type:** array of [GetListsResponseItem](#scalar-schema-getlistsresponseitem) | `null` 주소록 목록입니다. 주소록이 없으면 `null` 을 반환합니다. ### GetListsResponseItem **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | --------------------------- | ---------------------------------------- | | `$.id` | `1234` | | `$.owner` | `"abcd1234-ab12-cd34-ef56-abcdef123456"` | | `$.name` | `"내 주소록"` | | `$.senderName` | `"고길동"` | | `$.companyName` | `"회사명"` | | `$.companyContact` | `"0212341234"` | | `$.companyAddress` | `"서울시 중구 동호로"` | | `$.useSubscriberAutoDelete` | `true` | | `$.canSendToUnsubscribed` | `false` | | `$.useAutoDeletion` | `true` | **Type:** `object` - **`canSendToUnsubscribed`**: `boolean` 수신거부 구독자 발송 대상 포함 여부 - **`companyAddress`**: `string` 주소 - **`companyContact`**: `string` 전화번호 - **`companyName`**: `string`, default: `"회사명"` 회사명 또는 이름 - **`id`**: `integer` 주소록 아이디 - **`name`**: `string` 주소록 이름 - **`owner`**: `string`, format: `uuid` 주소록이 속한 워크스페이스 아이디 - **`senderName`**: `string` 기본 발신자 이름 - **`useAutoDeletion`**: `boolean`, deprecated 자동삭제 기능 사용 여부. `useSubscriberAutoDelete` 와 항상 같은 값입니다. 하위호환을 위해 유지되는 응답 전용 필드이므로 `useSubscriberAutoDelete` 를 사용하세요. 주소록을 생성·수정할 때는 `useSubscriberAutoDelete` 만 사용할 수 있습니다. - **`useSubscriberAutoDelete`**: `boolean` 자동삭제 기능 사용 여부 ### GetEmailsResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ---------- | ---- | | `$.total` | `8` | | `$.offset` | `0` | | `$.limit` | `8` | **Type:** `object` - **`items`**: array of [GetEmailResponse](#scalar-schema-getemailresponse) - **`limit`**: `integer` 기본 필드 - **`offset`**: `integer` 기본 필드 - **`total`**: `integer` 기본 필드 ### GetEmailResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | -------------------------- | ---------------------------------------- | | `$.id` | `123456` | | `$.status` | `3` | | `$.statusName` | `"SENT"` | | `$.type` | `1` | | `$.typeName` | `"NORMAL"` | | `$.listId` | `123456` | | `$.subject` | `"이메일 제목"` | | `$.permanentLink` | `"https://stib.ee/2eYF"` | | `$.segmentIds` | `[1234]` | | `$.groupIds` | `null` | | `$.sentTime` | `"2024-07-23T18:43:03+09:00"` | | `$.senderEmail` | `"gildong.go@stibee.com"` | | `$.senderName` | `"Gildong"` | | `$.owner` | `"abcd1234-ab12-cd34-ef56-abcdef123456"` | | `$.createdTime` | `"2024-07-19T17:56:06+09:00"` | | `$.subType` | `1` | | `$.subjectB` | `"B안 제목"` | | `$.senderNameB` | `"고길동B"` | | `$.permanentLinkSecondary` | `"https://stib.ee/3fZG"` | | `$.sentTimeB` | `"2024-07-23T20:43:03+09:00"` | | `$.abRatio` | `50` | **Type:** `object` - **`abRatio`**: `integer` A/B 테스트 비율(%). A/B 이메일이고 값이 있을 때만 포함됩니다. 값이 0이어도 필드 자체가 생략될 수 있습니다. - **`createdTime`**: `string`, format: `date-time` 이메일 생성 시간 - **`groupIds`**: `(array of integer) | null` - **`id`**: `integer` 이메일 아이디 - **`listId`**: `integer` 주소록 아이디 - **`owner`**: `string`, format: `uuid` 이메일 소유자 아이디 - **`permanentLink`**: `string`, format: `uri` 이메일 콘텐츠 링크(웹에서 보기) - **`permanentLinkSecondary`**: `string`, format: `uri` A/B 테스트 B안 콘텐츠 링크(웹에서 보기). A/B 이메일이고 값이 있을 때만 포함됩니다. 값이 없으면 필드 자체가 생략됩니다. - **`segmentIds`**: `array of integer` - **`senderEmail`**: `string`, format: `email` 발신자 이메일 주소 - **`senderName`**: `string` 발신자 이름 - **`senderNameB`**: `string` A/B 테스트용 B안 발신자 이름. A/B 이메일이고 값이 있을 때만 포함됩니다. 값이 없으면 필드 자체가 생략됩니다. - **`sentTime`**: `string`, format: `date-time` 이메일 발송 시간. 미발송 이메일(status: 0 등)은 아직 발송 시각이 없어 1990-01-01T00:00:00+09:00 으로 표시될 수 있습니다. 발송 여부는 status·statusName 으로 확인하세요. `sortBy=sentTime` 으로 정렬하면 이 값이 기준이 되므로 미발송 이메일은 내림차순에서 맨 뒤, 오름차순에서 맨 앞에 옵니다. 발송한 이메일만 보려면 `statuses=SENT` 를 함께 사용하세요. - **`sentTimeB`**: `string`, format: `date-time` A/B 테스트 B안 발송 시간. A/B 이메일이고 값이 있을 때만 포함됩니다. 값이 없으면 필드 자체가 생략됩니다. - **`status`**: `integer`, possible values: `0, 1, 3, 10, 11, 12, 13, 15, 21, 22, 23, 41, 42` 이메일의 상태 코드 (legacy 필드). 제거 일정은 없으며, 이름으로 다루려면 `statusName`을 사용하세요. - 0: 작성 중 - 1: 예약 - 3: 발송 완료 - 10: 자동 작성 중 - 11: 자동 발송 중 - 12: 자동 일시중지 - 13: 자동 중지 - 15: 자동 예약 - 21: 처리 중 - 22: 발송 중 - 23: 발송 지연 - 41: 실패 - 42: 스팸 ※ 21·22·23은 발송이 진행되는 동안 잠깐 거치는 상태입니다. - **`statusName`**: `string`, possible values: `"WRITING", "RESERVED", "SENT", "AUTO_DRAFT", "AUTO_SENDING", "AUTO_PAUSED", "AUTO_STOPPED", "AUTO_RESERVED", "PROCESSING", "SENDING", "SENDING_DELAYED", "FAILED", "SPAM", "UNKNOWN"` 이메일 상태 이름(`status`와 대응). 아래 목록에 없는 상태 코드는 `UNKNOWN`으로 내려갑니다. 새로 추가된 필드라 대문자 스네이크 표기(예: `SENT`)를 씁니다. 이미 공개된 값(예: 구독자 `status`)과 표기 방식이 다른 것은, 기존 값을 바꾸면 하위 호환이 깨지기 때문입니다. - WRITING: 작성 중 (status 0) - RESERVED: 예약 (status 1) - SENT: 발송 완료 (status 3) - AUTO_DRAFT: 자동 작성 중 (status 10) - AUTO_SENDING: 자동 발송 중 (status 11) - AUTO_PAUSED: 자동 일시중지 (status 12) - AUTO_STOPPED: 자동 중지 (status 13) - AUTO_RESERVED: 자동 예약 (status 15) - PROCESSING: 처리 중 (status 21) - SENDING: 발송 중 (status 22) - SENDING_DELAYED: 발송 지연 (status 23) - FAILED: 실패 (status 41) - SPAM: 스팸 (status 42) - UNKNOWN: 위 목록에 없는 상태 코드 - **`subject`**: `string` 이메일 제목 - **`subjectB`**: `string` A/B 테스트용 B안 제목. A/B 이메일이고 값이 있을 때만 포함됩니다. 값이 없으면 필드 자체가 생략됩니다. - **`subType`**: `integer` A/B 테스트 대상. A/B 이메일이고 값이 있을 때만 포함됩니다. 값이 없으면 필드 자체가 생략됩니다. 어떤 subType에서 어떤 B안 필드가 실제로 채워지는지는 보증하지 않습니다. - 1: 제목 (`subjectB`) - 2: 발신자명 (`senderNameB`) - 3: 발송시각 (`sentTimeB`) - 4: 콘텐츠 (`permanentLinkSecondary`) - **`type`**: `integer` 이메일 종류 - 1: 일반 이메일 - 2: A/B 이메일 - 3: 자동 이메일 - 4: 자동 문자 - **`typeName`**: `string`, possible values: `"NORMAL", "AB_TEST", "AUTO_MAIL", "AUTO_SMS", "UNKNOWN"` 이메일 종류 이름(`type`과 대응). 아래 목록에 없는 값은 `UNKNOWN`으로 내려갑니다. - NORMAL: 일반 이메일 (type 1) - AB_TEST: A/B 이메일 (type 2) - AUTO_MAIL: 자동 이메일 (type 3) - AUTO_SMS: 자동 문자 (type 4) - UNKNOWN: 위 목록에 없는 값 ### GetSubscribersVarsResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ----- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `$` | `[{"id":60723,"label":"이메일 주소","substitution":"email","defaultValue":"","isMandatory":true,"customLabel":"","type":"text","typeOption":{},"isVisible":false},{"id":60724,"label":"이름","substitution":"name","defaultValue":"","isMandatory":false,"customLabel":"","type":"text","typeOption":{},"isVisible":false}]` | **Type:** array of [GetSubscriberVarsResponse](#scalar-schema-getsubscribervarsresponse) **Example:** ```json [ { "id": 60723, "label": "이메일 주소", "substitution": "email", "defaultValue": "", "isMandatory": true, "customLabel": "", "type": "text", "typeOption": {}, "isVisible": false }, { "id": 60724, "label": "이름", "substitution": "name", "defaultValue": "", "isMandatory": false, "customLabel": "", "type": "text", "typeOption": {}, "isVisible": false } ] ``` ### GetSubscriberVarsResponse **Type:** `object` - **`customLabel`**: `string` 구독 화면에서 표시할 사용자 정의 필드 이름 - **`defaultValue`**: `string` 메일머지 치환자를 구독자 정보로 치환할 때, 저장된 값이 없을 때 사용하는 값 - **`id`**: `integer` 사용자 정의 필드 아이디 - **`isMandatory`**: `boolean` 필수 값 여부 - **`isVisible`**: `boolean` 필드 표시 여부 - **`label`**: `string` 사용자 정의 필드를 구분하기 위한 이름 - **`substitution`**: `string` 메일머지 치환자를 입력하거나 구독자 정보를 API로 전송할 때 사용하는 값 - **`type`**: `string` 사용자 정의 필드 유형(예. 텍스트, 드롭다운) - **`typeOption`**: `object` 사용자 정의 필드 유형에 따른 부가 옵션 ### CreateSubscriberVarRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ---------------- | ----------- | | `$.label` | `"Address"` | | `$.substitution` | `"addr"` | | `$.defaultValue` | `""` | | `$.isMandatory` | `false` | | `$.type` | `"text"` | **Type:** `object` - **`defaultValue` (required)**: `string` 메일머지 치환자를 구독자 정보로 치환할 때, 저장된 값이 없을 때 사용하는 값 - **`isMandatory` (required)**: `boolean` 필수 값 여부 - **`label` (required)**: `string` 사용자 정의 필드를 구분하기 위한 이름 - **`substitution` (required)**: `string` 메일머지 치환자를 입력하거나 구독자 정보를 API로 전송할 때 사용하는 값 - **`type` (required)**: `string` 사용자 정의 필드 유형(예. 텍스트, 드롭다운) ### CreatedCopiedEmailResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------ | ------- | | `$.id` | `60001` | **Type:** `object` - **`id` (required)**: `integer` 복사된 이메일 아이디 ### AddSenderRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | --------- | ------------------------- | | `$.email` | `"gildong.go@stibee.com"` | **Type:** `object` - **`email` (required)**: `string`, format: `email` 발신자 이메일 주소 ### AddSenderResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | -------------- | ------- | | `$.authorized` | `false` | **Type:** `object` - **`authorized` (required)**: `boolean` 추가하는 발신자 이메일의 인증 여부. false이면 발신자 이메일 주소로 인증 이메일이 발송됨. true이면 발송되지 않고 바로 추가됨. ### Subscriber **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ---------- | ------------------------- | | `$.email` | `"gildong.go@stibee.com"` | | `$.fields` | `{"name":"고길동"}` | **Type:** `object` - **`email` (required)**: `string`, format: `email` 구독자 이메일 주소 - **`status` (required)**: `string`, possible values: `"subscribed", "unsubscribed"` 구독자 상태 - subscribed: 구독 중 - unsubscribed: 수신거부 - **`fields`**: `object` 주소록에 생성된 사용자 정의 필드별 값 (주소록에 생성되어있는 필드만 값을 입력할 수 있음) - **`marketingAllowed`**: `boolean`, default: `false` 광고성 정보 수신동의 여부 ### BatchSubscriberRequest **Type:** `object` - **`subscribers` (required)**: array of [Subscriber](#scalar-schema-subscriber), maxItems: `1000` 추가할 구독자 목록 (최대 1,000명) - **`updateEnabled`**: `boolean`, default: `false` 구독자가 이미 존재할 경우 fields 값들의 업데이트 여부. false이면 업데이트하지 않음. true이면 새로 요청한 값으로 업데이트함. ### BatchSubscriberResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------------------- | --------------------------- | | `$.createdSubscribers` | `["gildong.go@stibee.com"]` | | `$.updatedSubscribers` | `["dooly@stibee.com"]` | | `$.failAlreadyExists` | `["gildong.go@stibee.com"]` | | `$.failNoEmails` | `[""]` | | `$.failInvalidEmails` | `["invalid-email"]` | | `$.failDuplicatedEmails` | `["dooly@stibee.com"]` | | `$.failInvalidFields` | `["gildong.go@stibee.com"]` | | `$.failInvalidSubscriberStatus` | `["dooly@stibee.com"]` | **Type:** `object` - **`createdSubscribers`**: `array of string` 추가 성공한 이메일 주소 목록 - **`failAlreadyExists`**: `(array of string) | null` (update가 false인 경우) 추가 실패 주소록에 이미 추가된 구독자임 - **`failDuplicatedEmails`**: `(array of string) | null` 추가 실패 - 요청 내 중복된 이메일 주소가 있음 - **`failInvalidEmails`**: `(array of string) | null` 추가 실패 - 이메일 주소 형식이 잘못됨 - **`failInvalidFields`**: `(array of string) | null` 추가 실패 - 사용자 정의 필드가 잘못됨 - **`failInvalidSubscriberStatus`**: `(array of string) | null` 추가 실패 - 구독 상태가 잘못됨 - **`failNoEmails`**: `(array of string) | null` 추가 실패 - 이메일 주소 필드에 값이 없음 - **`updatedSubscribers`**: `array of string` (update가 true인 경우) 업데이트 성공 주소록에 이미 추가된 구독자임. 이메일 주소와 구독 상태 외의 다른 정보를 업데이트함 ### UpdateEmailRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `$` | `{"type":1,"subType":2,"abRatio":60,"subject":"이메일 제목","subjectA":"이메일 제목 A","subjectB":"이메일 제목 B","senderEmail":"gildong.go@stibee.com","senderName":"고길동","senderNameA":"둘리","senderNameB":"희동이","listId":123,"segmentIds":[1,2,3],"groupIds":[4,5,6]}` | | `$.type` | `1` | | `$.subType` | `2` | | `$.abRatio` | `60` | | `$.subject` | `"Email Subject"` | | `$.subjectA` | `"Subject A"` | | `$.subjectB` | `"Subject B"` | | `$.senderEmail` | `"gildong.go@stibee.com"` | | `$.senderName` | `"Sender Name"` | | `$.senderNameA` | `"Sender Name A"` | | `$.senderNameB` | `"Sender Name B"` | | `$.listId` | `123` | | `$.segmentIds` | `[1,2,3]` | | `$.groupIds` | `[4,5,6]` | **Type:** `object` - **`abRatio`**: `integer`, minimum: `0`, maximum: `100` A/B 테스트 비율 - **`groupIds`**: `array of integer` 그룹 아이디 목록 - **`listId`**: `integer` 주소록 아이디 - **`segmentIds`**: `array of integer` 세그먼트 아이디 목록 - **`senderEmail`**: `string`, format: `email` 발신자 이메일 - **`senderName`**: `string` 발신자 이름 - **`senderNameA`**: `string` A/B 테스트용 A 발신자 이름 - **`senderNameB`**: `string` A/B 테스트용 B 발신자 이름 - **`subject`**: `string` 이메일 제목 - **`subjectA`**: `string` A/B 테스트용 A 제목 - **`subjectB`**: `string` A/B 테스트용 B 제목 - **`subType`**: `integer` 이메일 서브타입 - **`type`**: `integer` 이메일 타입 **Example:** ```json { "type": 1, "subType": 2, "abRatio": 60, "subject": "이메일 제목", "subjectA": "이메일 제목 A", "subjectB": "이메일 제목 B", "senderEmail": "gildong.go@stibee.com", "senderName": "고길동", "senderNameA": "둘리", "senderNameB": "희동이", "listId": 123, "segmentIds": [ 1, 2, 3 ], "groupIds": [ 4, 5, 6 ] } ``` ### EmailLogsResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `$.total` | `8` | | `$.offset` | `0` | | `$.limit` | `8` | | `$.items` | `[{"id":1,"subscriber":"gildong.go@stibee.com","action":"P","actionName":"DELIVERED","value":"","value2":"250\nok","createdTime":"2024-07-23T18:43:08+09:00"}]` | **Type:** `object` - **`items`**: array of [EmailLogItem](#scalar-schema-emaillogitem) 로그 아이템 목록 - **`limit`**: `integer` 한 번에 가져올 데이터의 최대 개수 - **`offset`**: `integer` 현재 데이터 조회가 시작되는 위치 - **`total`**: `integer` 조회 조건에 맞는 데이터의 총 개수 ### EmailLogItem **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | --------------- | ----------------------------- | | `$.id` | `1` | | `$.subscriber` | `"gildong.go@stibee.com"` | | `$.action` | `"P"` | | `$.actionName` | `"DELIVERED"` | | `$.value` | `""` | | `$.value2` | `"250\nok"` | | `$.createdTime` | `"2024-07-23T18:43:08+09:00"` | **Type:** `object` - **`action`**: `string`, possible values: `"P", "F", "A", "B", "D", "O", "C", "G", "V"` 구독자 활동 - P : 발송 성공 - F : 발송 실패(소프트바운스) - A : 발송 실패(하드바운스, 주소록 자동삭제 적용) - B : 발송 실패(하드바운스, 주소록 자동삭제 미적용) - D : 수신 거부 - O : 이메일 오픈 - C : 이메일 본문 내 링크 클릭 - G : 기부 완료 - V : 기부 페이지 유입 - **`actionName`**: `string`, possible values: `"DELIVERED", "SOFT_BOUNCED", "HARD_BOUNCED_DELETED", "HARD_BOUNCED", "UNSUBSCRIBED", "OPENED", "CLICKED", "DONATED", "DONATION_REDIRECT", "UNKNOWN"` 구독자 활동 이름(`action`과 대응). 아래 목록에 없는 값은 `UNKNOWN`으로 내려갑니다. 새로 추가된 필드라 대문자 스네이크 표기(예: `DELIVERED`)를 씁니다. - DELIVERED : 발송 성공 (action P) - SOFT_BOUNCED : 발송 실패, 소프트바운스 (action F) - HARD_BOUNCED_DELETED : 발송 실패, 하드바운스, 주소록 자동삭제 적용 (action A) - HARD_BOUNCED : 발송 실패, 하드바운스, 주소록 자동삭제 미적용 (action B) - UNSUBSCRIBED : 수신 거부 (action D) - OPENED : 이메일 오픈 (action O) - CLICKED : 이메일 본문 내 링크 클릭 (action C) - DONATED : 기부 완료 (action G) - DONATION_REDIRECT : 기부 페이지 유입 (action V) - UNKNOWN : 위 목록에 없는 값 - **`createdTime`**: `string`, format: `date-time` 구독자 활동 생성 시간 - **`id`**: `integer` 로그 아이디 - **`subscriber`**: `string`, format: `email` 구독자 이메일 - **`value`**: `string` 구독자 활동별 값 - action이 O이면, UserAgent 정보 - action이 C이면, 클릭한 URL - action이 G이면, 기부 항목 코드 - action이 V이면, 기부 유형 - **`value2`**: `string` 구독자 활동별 보조 값 - action이 C이면, UserAgent 정보 - action이 P, F, A, B이면, 발송 성공/실패 서버 응답값 - action이 G이면, 기부 금액 ### GetEmailStatsResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | --------- | --------------------------------------------------------------------------------------------------------------------------------------- | | `$.items` | `[{"emailId":1024,"recipientCount":21,"successCount":13,"failCount":8,"openCount":1,"clickCount":0,"openRate":7.692308,"clickRate":0}]` | **Type:** `object` - **`items`**: array of [EmailStats](#scalar-schema-emailstats) 이메일 성과 목록 ### EmailStats **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | ---------- | | `$.emailId` | `1024` | | `$.recipientCount` | `21` | | `$.successCount` | `13` | | `$.failCount` | `8` | | `$.openCount` | `1` | | `$.clickCount` | `0` | | `$.openRate` | `7.692308` | | `$.clickRate` | `0` | **Type:** `object` - **`clickCount`**: `integer` 링크를 클릭한 구독자 수(중복 제거). 한 구독자가 여러 번 클릭해도 1로 셉니다. - **`clickRate`**: `number`, format: `float` 클릭율(%). 발송 성공한 구독자 중 링크를 클릭한 구독자의 비율입니다. 최대 100입니다. - **`emailId`**: `integer` 이메일 아이디 - **`failCount`**: `integer` 발송 대상 중 성공하지 못한 수(반송 합계). `recipientCount − successCount`입니다. - 발송 중인 메일은 아직 발송되지 않은 수가 포함됩니다. - 하드/소프트 구분은 제공하지 않습니다. - **`openCount`**: `integer` 이메일을 연 구독자 수(중복 제거). 한 구독자가 여러 번 열어도 1로 셉니다. 오픈 횟수의 총합이 아닙니다. - **`openRate`**: `number`, format: `float` 오픈율(%). 발송 성공한 구독자 중 이메일을 연 구독자의 비율입니다. 최대 100입니다. - **`recipientCount`**: `integer` 발송 대상 수. - **`successCount`**: `integer` 발송 성공 수. `openRate`·`clickRate`의 분모입니다. ### QuerySubscriberStatsRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | -------------- | ------------------------- | | `$.subscriber` | `"gildong.go@stibee.com"` | | `$.emailIds` | `[1024,1025]` | **Type:** `object` - **`emailIds` (required)**: `array of integer` 집계할 이메일 아이디 목록. - 한 번에 최대 30개까지 지정할 수 있습니다. - 같은 아이디를 여러 번 넣어도 한 번만 집계합니다. - 이 주소록에 속하지 않은 이메일 아이디가 하나라도 있으면 요청 전체가 거절됩니다. - **`subscriber` (required)**: `string` 구독자 이메일 주소. 한 번에 한 명만 지정할 수 있습니다. - 앞뒤 공백은 무시됩니다. - 주소록에 없는 구독자를 지정해도 오류가 아닙니다. 활동 횟수가 모두 0인 응답이 반환됩니다. (`emailCount`는 집계를 시도한 이메일 수이므로 0이 아닙니다.) ### GetSubscriberStatsResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | -------------------- | ------------------------- | | `$.subscriber` | `"gildong.go@stibee.com"` | | `$.emailCount` | `12` | | `$.successCount` | `12` | | `$.openCount` | `7` | | `$.clickCount` | `3` | | `$.unsubscribeCount` | `0` | | `$.bounceCount` | `1` | **Type:** `object` - **`bounceCount`**: `integer` 발송 실패 활동 횟수. 소프트바운스(`action` F)와 하드바운스(`action` A, B)를 합한 값입니다. - **`clickCount`**: `integer` 이메일 본문 내 링크 클릭(`action` C) 활동 횟수 - **`emailCount`**: `integer` 집계한 이메일 수. 발송 기록이 없는 이메일은 제외됩니다. - **`openCount`**: `integer` 이메일 오픈(`action` O) 활동 횟수 - **`subscriber`**: `string` 요청한 구독자 이메일 주소 - **`successCount`**: `integer` 발송 성공(`action` P) 활동 횟수 - **`unsubscribeCount`**: `integer` 수신 거부(`action` D) 활동 횟수 ### CreateEmailRequest **Type:** `object` - **`listId` (required)**: `integer` 발송 대상 주소록 - **`senderEmail` (required)**: `string`, format: `email` 발신자 이메일 주소 - **`senderName` (required)**: `string` 발신자 이름 - **`subject` (required)**: `string` 이메일 제목 - **`groupIds`**: `array of integer` 발송 대상 그룹 - **`segmentIds`**: `array of integer` 발송 대상 세그먼트 ### CreateEmailResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------ | ------ | | `$.id` | `1234` | **Type:** `object` - **`id`**: `integer` 이메일 아이디 ### AddSubscriberRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | --------------------- | ------------------------- | | `$.subscriber.fields` | `{"name":"고길동","age":45}` | **Type:** `object` - **`subscriber` (required)**: `object` - **`email` (required)**: `string`, format: `email` 구독자 이메일 주소 - **`status` (required)**: `string`, possible values: `"subscribed", "unsubscribed"` 구독자 상태 - subscribed: 구독 중 - unsubscribed: 수신거부 - **`fields`**: `object` 주소록에 생성된 사용자 정의 필드별 값 (주소록에 생성되어있는 필드만 값을 입력할 수 있음) - **`marketingAllowed`**: `boolean`, default: `false` 광고성 정보 수신동의 여부 - **`updateEnabled`**: `boolean`, default: `false` 구독자가 이미 존재할 경우 fields 값들의 업데이트 여부. false이면 업데이트하지 않음. true이면 새로 요청한 값으로 업데이트함. ### GetListResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | --------- | ---------------------------------------- | | `$.owner` | `"abcd1234-ab12-cd34-ef56-abcdef123456"` | **Type:** `object` - **`canSendToUnsubscribed`**: `boolean` 수신거부 구독자 발송 대상 포함 여부 - **`companyAddress`**: `string` 주소 - **`companyContact`**: `string` 전화번호 - **`companyName`**: `string` 회사명 또는 이름 - **`id`**: `integer` 주소록 아이디 - **`name`**: `string` 주소록 이름 - **`owner`**: `string`, format: `uuid` 주소록이 속한 워크스페이스 아이디 - **`senderName`**: `string` 기본 발신자 이름 - **`useSubscriberAutoDelete`**: `boolean` 자동삭제 기능 사용 여부 ### UpdateListRequest **Type:** `object` - **`canSendToUnsubscribed`**: `boolean` 수신거부 구독자 발송 대상 포함 여부 - **`companyAddress`**: `string` 주소 - **`companyContact`**: `string` 전화번호 - **`companyName`**: `string` 회사명 또는 이름 - **`name`**: `string` 주소록 이름 - **`senderName`**: `string` 기본 발신자 이름 - **`useSubscriberAutoDelete`**: `boolean` 자동삭제 기능 사용 여부 ### SendDoubleOptinRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | --------------------- | ------------------------- | | `$.subscriber.fields` | `{"name":"고길동","age":45}` | **Type:** `object` - **`subscriber` (required)**: `object` - **`email` (required)**: `string`, format: `email` 구독자 이메일 주소 - **`fields`**: `object` 주소록에 생성된 사용자 정의 필드별 값 (주소록에 생성되어있는 필드만 값을 입력할 수 있음) ### GetSubscribersResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ---------------- | ------------------------------------------- | | `$.status` | `"subscribed"` | | `$.fields` | `{"$ad_agreed":"","age":"43","name":"고길동"}` | | `$.groupIds` | `[1,2]` | | `$.createdTime` | `"2024-11-12 17:09:13 +0900 KST"` | | `$.modifiedTime` | `"2024-11-17 20:01:11 +0900 KST"` | **Type:** `object` - **`createdTime`**: `string` 구독일 - **`email`**: `string`, format: `email` 구독자 이메일 - **`fields`**: `object` 사용자 정의 필드 값 - **`groupIds`**: `array of integer` 구독자가 속한 그룹 아이디 목록 - **`modifiedTime`**: `string` 수정일 - **`status`**: `string`, possible values: `"subscribed", "unsubscribed", "ready", "archived"` 구독자 구독 상태. 이미 공개된 값이라 소문자 표기를 유지합니다(신규 semantic 필드의 대문자 스네이크 표기와는 다릅니다). ### GetSubscriberCountResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | --------- | ------ | | `$.total` | `1234` | **Type:** `object` - **`total` (required)**: `integer` 전체 구독자 수 ### UpdateSubscriberRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ---------- | ---------------- | | `$.fields` | `{"name":"고길동"}` | **Type:** `object` - **`fields` (required)**: `object` 주소록에 생성된 사용자 정의 필드별 값 (주소록에 생성되어있는 필드만 값을 입력할 수 있음) ### AssignGroupRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | -------------- | ------------------------- | | `$.subscriber` | `"gildong.go@stibee.com"` | **Type:** `object` - **`subscriber` (required)**: `string`, format: `email` 구독자 이메일 ### ReleaseGroupRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | -------------- | ------------------------- | | `$.subscriber` | `"gildong.go@stibee.com"` | **Type:** `object` - **`subscriber` (required)**: `string`, format: `email` 구독자 이메일 ### DeleteSubscribersRequest **Type:** `object` - **`subscribers` (required)**: `array`, maxItems: `100` 삭제할 구독자 이메일 목록 - 한번에 최대 요청할 수 있는 개수는 100명 **Items:** `string`, format: `email` ### GetListSenderResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | -------------- | ------------------------- | | `$.email` | `"gildong.go@stibee.com"` | | `$.authorized` | `false` | **Type:** `object` - **`authorized`**: `boolean` 발신자 이메일의 인증 여부. false 이면 “email”로 수신된 인증메일을 통해 발신자 인증을 수행해야한다. - **`email`**: `string`, format: `email` 발신자 이메일 주소 ### CreateGroupRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | -------- | --------- | | `$.name` | `"그룹 이름"` | **Type:** `object` - **`name` (required)**: `string` 그룹 이름 ### CreateGroupResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------ | ------ | | `$.id` | `1234` | **Type:** `object` - **`id` (required)**: `integer` 그룹 아이디 ### GetGroupResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | --------------------- | ----------------------------- | | `$.items.id` | `1234` | | `$.items.name` | `"그룹 이름"` | | `$.items.createdTime` | `"2024-11-17T22:20:35+09:00"` | **Type:** `array` **Array of:** - **`createdTime`**: `string`, format: `date-time` 생성 일시 - **`id`**: `integer` 그룹 아이디 - **`name`**: `string` 그룹 이름 ### UpdateGroupRequest **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | -------- | --------- | | `$.name` | `"그룹 이름"` | **Type:** `object` - **`name` (required)**: `string` 그룹 이름 ### GetEmailsErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"잘못된 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Data.InvalidRequest", "Errors.Data.InvalidDateFormat", "Errors.Data.InvalidDateRange", "Errors.Data.LimitExceeded"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### CreateEmailErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"일반 이메일이 아닙니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Email.WrongEmailType", "Errors.Authorization.PermissionDenied"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### UpdateEmailErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied", "Errors.Email.WrongEmailType", "Errors.Data.InvalidRequest"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### GetEmailLogsErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"잘못된 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Data.InvalidRequest", "Errors.Data.LimitExceeded"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### GetEmailContentErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied", "Errors.Data.InvalidRequest", "Errors.Editor.NoHTMLExist"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### UpdateEmailContentErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"이메일 상태를 확인 하세요."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Email.WrongStatus"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### SendEmailErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied", "Errors.Email.WrongStatus", "Errors.List.ExceededSubscribers", "Errors.Email.Spamer", "Errors.Email.EmptySubscriber", "Errors.Service.NeedProPlan", "Errors.List.NoEmailActionSegmentAuthority", "Errors.List.TooManyGroups", "Errors.List.ExceededSubscriberVarLimit", "Errors.List.SegmentExceededLimit", "Errors.Email.ExceededAutomailCountLimit", "Errors.Email.IncompleteEmail"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### ReserveEmailErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied", "Errors.Data.InvalidRequest", "Errors.Email.WrongStatus", "Errors.List.ExceededSubscribers", "Errors.Email.Spamer", "Errors.Email.EmptySubscriber", "Errors.Service.NeedProPlan", "Errors.List.NoEmailActionSegmentAuthority", "Errors.List.TooManyGroups", "Errors.List.ExceededSubscriberVarLimit", "Errors.List.SegmentExceededLimit", "Errors.Email.ExceededAutomailCountLimit", "Errors.Email.IncompleteEmail"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### CreateListErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"잘못된 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Data.InvalidRequest"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### CopyListErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied", "Errors.Data.InvalidRequest", "Errors.List.NotUpdatableCanSendToUnsubscribed"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### GetListNotFoundResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `404` | | `$.message` | `"데이터가 없습니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Data.NoData"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### AddListSenderErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"잘못된 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Data.InvalidRequest", "Errors.Authorization.PermissionDenied", "Errors.List.NotPermittedSenderDomain"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### VerifyListSenderErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"잘못된 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Data.InvalidRequest", "Errors.Authorization.PermissionDenied", "Errors.List.NotExistEmail", "Errors.List.NotPermittedSenderDomain"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### AddSubscriberErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"잘못된 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Data.InvalidRequest", "Errors.Authorization.PermissionDenied", "Errors.List.NoEmail", "Errors.List.InvalidEmail", "Errors.List.InvalidSubscriberVar", "Errors.List.InvalidSubscriberStatus", "Errors.List.AlreadyExistEmail"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### GetSubscribersErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"요청 제한을 초과하였습니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Data.LimitExceeded", "Errors.Authorization.PermissionDenied"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### DeleteSubscribersErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied", "Errors.Data.LimitExceeded"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### SendDoubleOptinErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"잘못된 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Data.InvalidRequest", "Errors.Authorization.PermissionDenied", "Errors.List.NoEmail", "Errors.List.InvalidEmail", "Errors.List.InvalidSubscriberVar", "Errors.List.InvalidSubscriberStatus", "Errors.List.AlreadyExistEmail", "Errors.List.NotExistEmail"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### BatchAddSubscribersErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied", "Errors.Data.InvalidRequest", "Errors.Data.TooLongData", "Errors.Data.LimitExceeded"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### AssignGroupErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied", "Errors.List.NotExistEmail", "Errors.List.NoSuchGroup", "Errors.Data.Duplicated"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### CreateGroupErrorResponse **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied", "Errors.Data.InvalidRequest", "Errors.List.AlreadyExistGroup", "Errors.List.TooManyGroups"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### SharedErrorResponse_3a6c2c2fa6 **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### SharedErrorResponse_d07945da9c **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"잘못된 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Data.MissingRequiredField", "Errors.Data.InvalidRequest", "Errors.Data.LimitExceeded", "Errors.Authorization.PermissionDenied"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### SharedErrorResponse_6427954453 **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied", "Errors.Data.InvalidRequest"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### SharedErrorResponse_d9bfb03eb3 **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"잘못된 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Data.InvalidRequest", "Errors.Authorization.PermissionDenied"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다. ### SharedErrorResponse_b33e216723 **원본에 명시된 스키마·필드 예시** | 필드 경로 | 예시 값 | | ------------------ | -------------------------------------- | | `$.httpStatusCode` | `400` | | `$.message` | `"허용되지 않은 요청입니다."` | | `$.values` | `{"message":"무엇이 잘못되었는지 알려주는 상세 메시지"}` | **Type:** `object` - **`code` (required)**: `string`, possible values: `"Errors.Authorization.PermissionDenied", "Errors.List.NotExistEmail"` 에러 코드 - **`httpStatusCode` (required)**: `integer` HTTP 상태 코드 - **`message` (required)**: `string` 에러 메시지 - **`values`**: `object` 에러의 상세 정보입니다. 에러에 따라 포함되지 않을 수 있습니다.