Skip to Content
개발자뉴스레터 API

뉴스레터 API

뉴스레터 API는 이메일 뉴스레터의 구독자 명단캠페인(작성 → 예약·발송 → 취소)을 관리합니다. 구독자·캠페인 엔드포인트는 대시보드 API 계열로, Authorization: Bearer 헤더에 JWT 액세스 토큰을 담아 호출합니다. 토큰 발급과 역할(RBAC)은 대시보드 인증을 참고하세요. 수신거부 엔드포인트는 알림 API 계열의 무인증 공개 엔드포인트로 이메일 본문의 수신거부 링크가 호출하며, 지원 채널은 현재 email 하나입니다.

구독자·캠페인 API(대시보드 API)의 성공 응답은 봉투 없이 컨트롤러가 반환한 JSON을 그대로 내려주고, 공개 수신거부 API(알림 API 계열)의 JSON 응답은 data / meta 봉투(envelope) 로 감싸집니다. 에러는 두 계열 모두 RFC 7807 application/problem+json 형식입니다(에러 코드 참고).

권한 경계

작업필요 역할
구독자·캠페인 조회(목록/상세/대상 미리보기)viewer 이상 (owner / admin / operator / viewer)
구독자 생성·일괄 등록·수정, 캠페인 생성·수정·발송·취소operator 이상 (owner / admin / operator)
구독자 삭제, 캠페인 삭제owner, admin

캠페인 상태

상태의미
draft작성 중, 미발송. 유일하게 수정 가능한 상태입니다.
scheduled예약 발송 대기. 팬아웃 잡이 scheduledAt까지 지연됩니다.
sending발송 진행 중. 팬아웃(수신자별 요청 생성·큐 적재)과 전달이 진행됩니다.
sent모든 수신자가 종료 상태에 도달했습니다.
canceled발송 취소됨.
failed팬아웃 자체 실패.
  • 발송을 트리거하면 draft → sending(즉시) 또는 draft → scheduled → sending(예약)으로 전이하며, scheduled / sending은 취소 API로 canceled가 될 수 있습니다.
  • sending(또는 scheduled) → sent 전이는 캠페인 상세 조회 시점에 판정됩니다. 대기 중인 요청(queued + processing)이 0이 되면 조회 시 sent로 전이되고 finishedAt이 기록됩니다.

구독자 동의 상태

상태의미발송 대상
subscribed수신동의 완료O
unsubscribed수신거부X
pending동의 확인 전(더블 옵트인 대기 등)X

동의 상태를 전이하면 정보통신망법 대응을 위한 시각이 자동 기록됩니다. subscribed로 전환하면 consentedAt이 기록되고 unsubscribedAtnull로 초기화되며, unsubscribed로 전환하면 unsubscribedAt이 기록됩니다.

구독자

구독자 목록 조회

GEThttps://api.posmit.io/v1/newsletter/subscribers

워크스페이스의 구독자 목록을 최신 등록순으로 조회합니다. (역할: owner / admin / operator / viewer)

쿼리타입설명
channelstring선택. 현재 email만 유효합니다.
consentStatusstring선택. subscribed / unsubscribed / pending 필터.
searchstring선택(최대 320자). 주소·이름 부분 일치 검색.
limitint선택. 1 ~ 200, 기본 50.
offsetint선택. 기본 0.
{ "subscribers": [ { "id": "…", "channel": "email", "address": "user@example.com", "…": "…" } ], "total": 120, "limit": 50, "offset": 0 }

구독자 단건 조회

GEThttps://api.posmit.io/v1/newsletter/subscribers/:id

구독자 1명을 조회합니다. 응답은 { "subscriber": { … } } 형태이며, 워크스페이스에 해당 ID의 구독자가 없으면 404가 반환됩니다. (역할: owner / admin / operator / viewer)

구독자 생성

POSThttps://api.posmit.io/v1/newsletter/subscribers

구독자 1명을 등록합니다. (역할: owner / admin / operator)

필드타입필수설명
channelstring필수현재 email만 지원합니다.
addressstring필수이메일 주소(최대 320자). 앞뒤 공백 제거 후 소문자로 정규화되어 저장됩니다.
namestring선택최대 120자.
consentStatusstring선택기본 subscribed. 전환 시각이 자동 기록됩니다.
consentSourcestring선택동의 출처 메모(최대 60자).
attributesobject선택문자열 key-value. 캠페인 본문의 {{변수}} 치환과 세그먼트 필터에 사용됩니다.

등록 시 주소 도메인의 MX(폴백 A) 레코드를 DNS로 조회해 수신 가능성을 검증하며, 구독자마다 수신거부 토큰이 자동 발급됩니다.

curl -X POST https://api.posmit.io/v1/newsletter/subscribers \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "channel": "email", "address": "user@example.com", "name": "홍길동", "attributes": { "등급": "VIP" } }'
상태조건
400이메일 형식이 올바르지 않거나, 도메인에 MX 레코드가 없어 수신 불가한 경우.
409같은 워크스페이스에 동일 채널·주소의 구독자가 이미 존재합니다.

구독자 일괄 등록(임포트)

POSThttps://api.posmit.io/v1/newsletter/subscribers/import

여러 구독자를 한 번에 등록·갱신합니다. (역할: owner / admin / operator)

필드타입필수설명
subscribersarray필수1 ~ 5,000건. 각 항목: channel(필수) / address(필수, 최대 320자) / name(선택) / attributes(선택).
consentStatusstring선택목록 전체에 적용할 동의 상태. 기본 subscribed.
consentSourcestring선택목록 전체에 적용할 동의 출처(최대 60자).

같은 채널·주소의 구독자가 이미 있으면 갱신(updated), 없으면 생성(created)되며, 형식 오류 등 개별 항목의 실패는 전체를 막지 않고 건너뛰어 skipped로 집계됩니다. 주소는 단건 생성과 동일하게 소문자로 정규화되지만, MX 레코드 검증은 수행하지 않습니다.

{ "total": 1000, "created": 830, "updated": 150, "skipped": 20 }
상태조건
400subscribers가 비어 있거나 5,000건을 초과하는 등 요청 검증 실패.

구독자 수정

PATCHhttps://api.posmit.io/v1/newsletter/subscribers/:id

구독자의 name / consentStatus / consentSource / attributes를 수정합니다. (역할: owner / admin / operator) channeladdress는 변경할 수 없으며 이 필드를 보내면 400, 구독자가 없으면 404가 반환됩니다. consentStatus 변경 시 consentedAt / unsubscribedAt이 자동 기록됩니다.

구독자 삭제

DELETEhttps://api.posmit.io/v1/newsletter/subscribers/:id

구독자를 삭제하며, 성공 시 본문 없이 204가 반환됩니다. (역할: owner / admin)

캠페인

캠페인 목록 조회

GEThttps://api.posmit.io/v1/newsletter/campaigns

캠페인 목록을 최신 생성순으로 조회합니다. (역할: owner / admin / operator / viewer) 쿼리는 status(상태 필터), limit(1~200, 기본 50), offset(기본 0)을 지원하며, 응답은 { "campaigns": […], "total": …, "limit": …, "offset": … } 형태입니다.

캠페인 상세 조회

GEThttps://api.posmit.io/v1/newsletter/campaigns/:id

캠페인 1건을 발송 집계와 함께 조회합니다. (역할: owner / admin / operator / viewer)

{ "campaign": { "id": "…", "name": "7월 뉴스레터", "channel": "email", "status": "sending", "totalRecipients": 1200, "queuedCount": 1195, "failedCount": 5, "audienceSize": 1210, "deliveryStats": { "queued": 300, "processing": 20, "sent": 860, "failed": 15 }, "…": "…" } }
  • totalRecipients / queuedCount / failedCount는 팬아웃 진행 상황이 배치마다 반영되는 카운터입니다.
  • deliveryStats는 수신자별 발송 요청의 상태별 집계입니다 (queued / processing / sent / failed / canceled, unknown은 요청 미생성).
  • audienceSize현재 세그먼트 조건에 맞는 발송 대상 수로, 발송 시점과 다를 수 있습니다. 이 조회 시점에 대기 요청이 0이면 캠페인이 sent로 지연 전이됩니다.

발송 대상 미리보기

GEThttps://api.posmit.io/v1/newsletter/campaigns/:id/audience

발송 전에 세그먼트 조건에 맞는 대상 수를 확인합니다. 응답은 { "audienceSize": 1210 }입니다. (역할: owner / admin / operator / viewer)

캠페인 생성

POSThttps://api.posmit.io/v1/newsletter/campaigns

캠페인을 draft 상태로 생성합니다. (역할: owner / admin / operator)

필드타입필수설명
namestring필수1 ~ 200자.
channelstring필수현재 email만 지원합니다.
subjectstring조건부최대 200자. 이메일 캠페인은 필수(없으면 400).
contentTextstring필수1 ~ 100,000자. 구독자 attributes 기반 {{변수}} 치환을 지원합니다(한글 변수명 가능, 값이 없으면 빈 문자열).
contentHtmlstring선택최대 500,000자. HTML 본문.
isAdvertisementboolean선택기본 true. 광고성 정보 여부.
includeUnsubscribeboolean선택기본 true. 수신거부 안내 포함 여부. 비광고성 캠페인에서만 false로 끌 수 있습니다.
audienceFilterobject선택세그먼트 조건. { "attributes": { "등급": "VIP" } } 형태로 attributes 매칭에 사용됩니다. 내용 검증은 생성이 아니라 발송·조회 시점에 수행됩니다
scheduledAtstring선택ISO-8601 예약 시각. 미래 시각이어야 합니다.

isAdvertisement: true(기본값)이면 발송 시 제목에 (광고) 표기가 자동으로 붙고(이미 있으면 중복 표기하지 않음), includeUnsubscribe 값과 무관하게 본문 하단에 수신거부 안내 footer가 항상 강제 포함됩니다. 비광고성 캠페인만 includeUnsubscribe: false로 footer를 제외할 수 있습니다.

상태조건
400이메일 캠페인에 subject 누락, scheduledAt이 과거이거나 형식 오류.

캠페인 수정

PATCHhttps://api.posmit.io/v1/newsletter/campaigns/:id

캠페인을 수정합니다. draft 상태에서만 가능합니다. (역할: owner / admin / operator) 생성과 같은 필드를 부분 수정할 수 있으나 channel은 변경할 수 없습니다(보내면 400). scheduledAtnull을 보내면 예약이 해제됩니다.

상태조건
400channel 등 허용되지 않은 필드 포함, scheduledAt이 과거이거나 형식 오류.
404캠페인을 찾을 수 없습니다.
409draft가 아닌 캠페인은 수정할 수 없습니다.

캠페인 발송

POSThttps://api.posmit.io/v1/newsletter/campaigns/:id/send

캠페인 발송을 트리거합니다. draft / scheduled 상태에서만 가능합니다. (역할: owner / admin / operator)

필드타입필수설명
scheduledAtstring선택ISO-8601 예약 시각(미래). 생략 시 캠페인에 저장된 예약 시각(미래인 경우)을 사용하고, 그것도 없으면 즉시 발송합니다.

발송 대상 산정 규칙 — 다음을 모두 만족하는 구독자가 대상입니다. 캠페인과 같은 channel이고, consentStatussubscribed이며, 이메일 수신 차단 목록(영구 반송·수신자 불만으로 등록된 suppression 주소)에 없고, audienceFilter.attributes의 모든 key-value를 구독자 attributes가 포함(containment 매칭)해야 합니다.

audienceFilter{ "attributes": { "키": "값" } } 형태이며, 값으로 문자열·숫자·불리언을 쓸 수 있고 숫자·불리언은 문자열로 변환되어 매칭됩니다.

attributes를 지정했는데 유효한 조건이 하나도 없으면(빈 객체, 배열, 값이 전부 문자열·숫자·불리언이 아닌 경우) 필터가 없는 것으로 보고 전체 구독자에게 보내는 대신 발송을 막습니다(fail-closed). 이때 발송·미리보기·상세 조회는 400 NOTI-40000(audienceFilter.attributes must contain at least one string/number/boolean value)으로 거부됩니다. 다만 attributes 키 자체를 넣지 않은 그 밖의 필드는 조건으로 해석되지 않고 무시되므로, 이 경우에는 채널 전체 구독자가 대상이 됩니다.

검증 후 팬아웃 잡을 큐에 적재하고 즉시 반환하며, 실제 수신자별 요청 생성은 워커가 비동기로 수행합니다. 워커는 구독자를 500명 배치로 읽어 배치 안에서 20건씩 동시 처리하고, 진행 카운터를 배치마다 캠페인에 반영합니다. 팬아웃은 멱등해서 잡이 재시도되어도 이미 큐에 적재된 구독자는 건너뛰므로 중복 발송되지 않습니다.

curl -X POST https://api.posmit.io/v1/newsletter/campaigns/CAMPAIGN_ID/send \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "scheduledAt": "2026-07-15T09:00:00.000Z" }'
{ "campaignId": "…", "status": "scheduled", "audienceSize": 1210, "scheduledAt": "2026-07-15T09:00:00.000Z", "fanoutJobId": "1024" }
상태조건
400발송 대상이 0명, audienceFilter.attributes에 유효한 조건이 없음(fail-closed), 이메일 캠페인에 subject 누락, scheduledAt이 과거이거나 형식 오류.
404캠페인을 찾을 수 없습니다.
409draft / scheduled 외 상태에서는 발송할 수 없습니다.

캠페인 취소

POSThttps://api.posmit.io/v1/newsletter/campaigns/:id/cancel

발송을 취소합니다. scheduled / sending 상태에서만 가능하며, 그 외 상태에서는 409가 반환됩니다. (역할: owner / admin / operator) 아직 실행되지 않은 예약 팬아웃 잡을 제거하고, 이미 생성된 발송 요청 중 종료되지 않은 건(sent / failed / canceled 제외)을 취소하지만, 이미 전달 완료된 메일은 되돌릴 수 없습니다.

{ "campaignId": "…", "status": "canceled", "canceledRequests": 850 }

캠페인 삭제

DELETEhttps://api.posmit.io/v1/newsletter/campaigns/:id

캠페인을 삭제합니다. draft / canceled / failed 상태에서만 가능하며, 성공 시 204가 반환됩니다. (역할: owner / admin) scheduled / sending / sent 캠페인은 삭제할 수 없고(409), 예약·발송 중이라면 먼저 취소해야 합니다.

수신거부 (공개 엔드포인트)

수신거부 엔드포인트는 인증이 없으며, 이메일 footer의 수신거부 링크에 포함된 토큰이 구독자를 식별·인가합니다. 수신거부가 확정되면 구독자의 consentStatusunsubscribed로 바뀌고 unsubscribedAt이 기록됩니다.

메일 보안 스캐너와 이메일 클라이언트는 본문의 링크를 미리 GET으로 따라가 봅니다. 이때 수신거부가 자동으로 처리되는 것을 막기 위해 GET은 상태를 바꾸지 않고 확인 페이지만 보여주며, 실제 수신거부는 사용자가 버튼을 눌러 POST할 때만 확정됩니다.

수신거부 확인 페이지 (GET)

GEThttps://api.posmit.io/v1/newsletter/unsubscribe?token=...

수신거부 링크 클릭 시 호출되어 HTML 확인 페이지를 반환하며, 이 요청만으로는 수신거부가 처리되지 않습니다. 페이지의 확인 버튼이 아래 확정 엔드포인트로 token을 POST합니다. 토큰이 없거나 형식이 잘못되어도 정보 노출을 피하기 위해 에러 대신 항상 200과 안내 페이지(“수신거부 링크가 유효하지 않습니다”)를 반환합니다.

수신거부 확정 — 폼 (POST)

POSThttps://api.posmit.io/v1/newsletter/unsubscribe/confirm

확인 페이지의 폼이 제출하는 엔드포인트로, 수신거부를 처리하고 HTML 결과 페이지를 반환합니다. 본문은 application/x-www-form-urlencoded 형식의 token 한 필드이며, 토큰이 유효하지 않아도 항상 200과 안내 페이지를 반환합니다.

수신거부 확정 — 프로그램적 (POST)

POSThttps://api.posmit.io/v1/newsletter/unsubscribe

List-Unsubscribe의 원클릭 수신거부 등 프로그램적 호출에 사용하는 JSON 엔드포인트로, 이 호출은 수신거부를 즉시 확정합니다.

필드타입필수설명
tokenstring필수수신거부 토큰(최대 64자).
{ "data": { "unsubscribed": true }, "meta": { "timestamp": "2026-07-11T09:00:00.000Z" } }

토큰이 유효하지 않으면 200에 "unsubscribed": false가 반환됩니다. 이미 수신거부된 구독자의 토큰은 true를 반환하며 멱등하게 동작합니다. 두 POST 엔드포인트 모두 token이 비어 있거나 64자를 초과하면 400으로 거부되며, 이는 형식이 맞는 토큰이 단지 존재하지 않는 경우(200)와 구분됩니다.

대시보드 화면에서의 구독자 관리·캠페인 발송 사용법은 가이드 › 뉴스레터를 참고하세요.

Last updated on