발송

발송 플로우

접수(202) → 폴링 → 건별 결과까지. 접수 성공이 발송 성공이 아닌 이유.

발송은 한 번의 호출로 끝나지 않습니다. 접수와 도달이 다른 사건이라 접수 성공은 발송 성공이 아닙니다. 이 페이지는 그 사이에 무슨 일이 일어나는지와, 결과를 어떻게 확인하는지를 설명합니다.

전체 흐름

  1. 접수 (202)

    발송 API 를 부르면 서버가 수신자 목록을 받아 두고 곧바로 202 를 돌려줍니다. 이 시점에 이미 끝난 일이 있습니다 — 수신거부 대조, 중복 제거, 그리고 포인트 홀드.
  2. 발송

    큐에 올라간 잡이 실제로 통신사·카카오로 나갑니다. 건수가 많으면 시간이 걸립니다.
  3. 결과 확정

    건별 결과가 돌아오면서 성공·실패가 정해집니다. 실패한 건의 홀드는 풀리고, 성공한 건만 실제로 차감됩니다.
  4. 폴링으로 확인

    발송 그룹 결과를 주기적으로 조회해 상태가 끝났는지 봅니다.

접수 응답에서 봐야 할 것

필드뜻
groupId결과 조회의 열쇠입니다. 반드시 저장하세요 — 이 값이 없으면 무엇이 어떻게 됐는지 알 방법이 없습니다.
sendCount실제로 나가는 건수입니다. 요청한 수보다 적을 수 있습니다 — 수신거부와 중복이 이미 빠진 값입니다.
optOutExcluded수신거부로 빠진 수. 몇 명이 제외됐는지 알려 줍니다.
holdAmount선차감으로 잡아 둔 포인트입니다. 확정 차감액이 아니라 상한이며, 실패한 건만큼은 나중에 풀립니다.

폴링

결과는 폴링으로만 받습니다 — 웹훅은 제공하지 않습니다. status 가 아래 셋 중 하나가 되면 더 이상 바뀌지 않으니 거기서 멈추면 됩니다.

  • COMPLETED — 발송이 끝났습니다. 건별 성공·실패는 counts 에 있습니다.
  • FAILED — 잡 자체가 실패했습니다. failedReason 을 보세요.
  • CANCELED — 예약이 취소됐습니다.
const FINISHED = ["COMPLETED", "FAILED", "CANCELED"];

async function waitForResult(groupId) {
  // 5초 간격, 최대 10분. 너무 잦으면 8628(호출 한도)로 막힙니다.
  for (let attempt = 0; attempt < 120; attempt += 1) {
    const response = await fetch(
      `https://api.directalk.io/public/v1/messages/${groupId}`,
      { headers: { "Authorization": `Bearer ${apiKey}` } },
    );
    const { data } = await response.json();

    if (FINISHED.includes(data.status)) return data;

    await new Promise((resolve) => setTimeout(resolve, 5_000));
  }
  throw new Error("결과 확정이 너무 오래 걸립니다.");
}

건별 결과

누가 못 받았는지까지 알아야 한다면 개별 메시지 결과를 씁니다. 커서 페이지네이션이라 nextCursor 가 null 이 될 때까지 이어서 부르면 됩니다. 실패한 건만 보려면 filter=FAILED 를 붙이세요.

도달하지 못했다면

알림톡은 카카오 계정이 없거나 차단한 경우 도달하지 않습니다. 그때 문자로 대신 보내려면 대체발송을 켜 두세요 — 실패를 확인한 뒤 다시 보내는 것보다 빠르고, 홀드 계산도 한 번에 끝납니다.