결과 조회 · 예약 취소

접수한 발송 건의 진행 상태와 수신자별 최종 결과를 조회하고, 아직 발송되지 않은 예약 건을 취소합니다. 결과를 실시간으로 받고 싶다면 Webhook 을 함께 사용하세요.

조회·취소 대상은 API 로 접수한 건뿐입니다. 같은 계정이 웹사이트에서 발송한 건은 이 API 로 조회·취소할 수 없고 404 MESSAGE_NOT_FOUND 로 응답하며, 목록에도 나타나지 않습니다. (웹사이트의 발송 이력에서는 API 로 접수한 건에 API 표시가 붙습니다.)

상태 값

발송 건(message) 상태

status의미
ACCEPTED접수됨, 발송 대기/진행 전
SCHEDULED예약 접수됨 (발송 시각 전)
PROCESSING발송 처리 중
PARTIAL일부 수신자만 처리 완료
COMPLETED모든 수신자의 결과가 확정됨
CANCELLED취소됨

수신자(recipient) 상태

status의미최종?
PENDING발송 대기 (예약 포함)아니오
SENDING발송 처리 중아니오
SUBMITTED통신사/카카오에 전달됨, 도달 결과 대기아니오
DELIVERED수신 확인(성공)예
FAILED실패 — 요금 자동 환불예
REJECTED발송 대행 시스템이 접수 자체를 거절 — 요금 자동 환불예
CANCELLED예약 취소됨 — 요금 환불예

통신사 사정에 따라 SUBMITTED 에서 최종 결과가 확정되기까지 시간이 걸릴 수 있습니다. (대부분 수 초 이내) 최종 상태가 되기 전까지는 폴링하거나 Webhook 을 기다리세요.

발송 건 상세

GET /v1/messages/{message_id}
JSON
{
  "request_id": "req_b5e9af0145c737cec045",
  "data": {
    "message_id": 1375,
    "channel": "sms",
    "status": "COMPLETED",
    "name": "11/06 21:35 - 출고 안내",
    "from": "0212345678",
    "client_ref": "ship-20261107-am",
    "request_id": "req_e8cfaea0a9c54b8a3e10",
    "send_at": "2026-11-07T09:00:00+09:00",
    "counts": { "total": 2, "delivered": 1, "failed": 1, "pending": 0 },
    "amount": 10.5,
    "created_at": "2026-11-06T21:35:51+09:00"
  }
}

counts.pending 이 0 이 되면 모든 결과가 확정된 것입니다. amount 는 환불을 반영한 실제 청구 금액입니다.

수신자별 결과

GET /v1/messages/{message_id}/recipients
쿼리설명
status수신자 상태 필터
to특정 수신번호만 조회
limit1~1000 (기본 100)
cursor이전 응답의 paging.next_cursor
JSON
{
  "request_id": "req_…",
  "data": [
    {
      "recipient_id": 3304887,
      "to": "01011112222",
      "status": "DELIVERED",
      "client_ref": "A-1001",
      "result": { "code": "4100", "message": "전달", "carrier": "SKT" },
      "send_at": "2026-11-07T09:00:00+09:00",
      "sent_at": "2026-11-07T09:00:02+09:00",
      "delivered_at": "2026-11-07T09:00:05+09:00",
      "charged": 10.5
    }
  ],
  "paging": { "next_cursor": null }
}
  • result.code 는 통신사/카카오 결과 코드, result.message 는 그 설명입니다. 코드 목록은 결과 코드표 를 참고하세요. REJECTED 는 코드가 REJECTED 로 고정됩니다.
  • charged 는 이 수신자에게 청구된 금액입니다. 실패·취소 건은 환불되므로 정산은 status 와 함께 해석하세요.
  • 페이지가 더 있으면 paging.next_cursor 값이 채워집니다. 그 값을 cursor 로 넘겨 다음 페이지를 읽고, null 이면 끝입니다.
Python — 전체 수신자 결과 수집
def fetch_all_recipients(session, message_id):
    cursor, out = None, []
    while True:
        params = {"limit": 1000}
        if cursor:
            params["cursor"] = cursor
        r = session.get(f"https://api-01.redbean8.io.kr/v1/messages/{message_id}/recipients", params=params, timeout=30)
        r.raise_for_status()
        body = r.json()
        out += body["data"]
        cursor = body["paging"]["next_cursor"]
        if not cursor:
            return out

발송 목록

GET /v1/messages
쿼리설명
from, to접수 시각 범위 (ISO 8601). 기본: 최근 7일. 한 번에 최대 31일
statusACCEPTED · SCHEDULED · PROCESSING · PARTIAL · COMPLETED · CANCELLED
channelsms · lms · mms · alimtalk · brand
client_ref요청 참조키로 검색 (지정 시 기간 조건은 무시)
limit1~100 (기본 20)
cursor다음 페이지 커서

응답은 data 에 발송 건 상세와 같은 항목의 배열, paging.next_cursor 로 구성됩니다. 최신순으로 정렬됩니다.

예약 취소

POST /v1/messages/{message_id}/cancel

예약 시각이 아직 지나지 않았고 발송 대기 중인 수신자를 모두 취소하고 요금을 환불합니다.

JSON — 200 OK
{
  "request_id": "req_a2b3c74d17246af7aa5f",
  "data": {
    "message_id": 1374,
    "cancelled": 1,
    "refunded": 10.5,
    "not_cancellable": 0
  }
}
  • cancelled: 취소된 수신자 수, refunded: 환불 금액, not_cancellable: 이미 발송 처리가 시작되어 취소할 수 없는 수신자 수
  • 취소할 수 있는 건이 하나도 없으면 409 CANCEL_NOT_ALLOWED 입니다. (이미 발송 시작 / 이미 취소)
  • 브랜드메시지는 취소할 수 없습니다 (422 CANCEL_NOT_ALLOWED).
  • 취소된 수신자는 Webhook 으로 message.cancelled 이벤트가 전송됩니다.
  • 발송 시각 직전에는 이미 큐에 적재되었을 수 있으므로, 최소 1~2분 전에 취소하세요.

폴링 권장 방식

  • 접수 직후부터 최대 수 분간 5~10초 간격으로 GET /v1/messages/{id} 를 호출하여 counts.pending == 0 을 확인합니다.
  • 대량 발송 결과는 /recipients?status=FAILED 처럼 상태로 좁혀 가져오면 응답이 작아집니다.
  • 조회도 API 키 단위 요청 제한(분당 300회)에 포함됩니다. 가능하면 Webhook 을 사용하세요.