2026-08-09

요금제, 삭제 대신 "판매 중단" 해야 하는 이유

요금제를 개편하거나 실수로 잘못 만든 요금제를 정리하려 할 때, 가장 먼저 떠오르는 방법은 삭제입니다. 하지만 이미 그 요금제로 구독 중인 고객이 있다면 삭제는 생각보다 위험한 조작입니다. 이 글은 슈퍼빌링이 삭제 대신 "판매 중단(archive)"이라는 별도 상태를 만든 이유와, 실제로 어떻게 동작하는지를 다룹니다.

삭제가 위험한 이유

요금제를 삭제하면 그 요금제를 참조하는 구독·인보이스 레코드가 고아 데이터가 되거나, FK 제약이 걸려 있다면 삭제 자체가 실패합니다. 슈퍼빌링도 처음엔 이 케이스를 제대로 처리하지 못해 구독 중인 요금제를 삭제하려 하면 500 에러로 크래시가 났습니다. FK 제약(23503)이 DB 레벨에서 삭제를 막고 있었지만, 그 실패가 사용자에게는 원인을 알 수 없는 서버 에러로만 보였던 겁니다.

문제는 에러 메시지만이 아니었습니다. 근본적으로 "구독자가 있는 요금제를 지우고 싶다"는 요청 자체가 대부분의 경우 진짜 의도와 다릅니다. 실제로 원하는 건 보통 "이 요금제로 신규 가입은 막되, 기존 구독자는 그대로 유지하고 싶다"입니다.

판매 중단(archive)이라는 중간 상태

그래서 슈퍼빌링은 plans.archived_at 컬럼을 추가해 삭제와 별개의 상태를 만들었습니다.

  • 판매 중단된 요금제: 신규 구독 생성만 막힙니다. 임베드 위젯, 결제 콜백 양쪽에서 이 요금제로의 신규 가입 시도를 차단합니다.
  • 기존 구독자: 아무 영향 없습니다. 다음 결제일에도 똑같이 청구되고, 던닝 로직도 동일하게 적용됩니다.
  • 원복 가능: "다시 판매하기"로 즉시 신규 가입을 재개할 수 있습니다. 삭제와 달리 되돌릴 수 있는 조작입니다.

대시보드에서 삭제를 시도했다가 구독자가 있어 실패하면, 자동으로 "신규 가입 중단하기"를 제안하는 흐름으로 안내합니다. 사용자가 "삭제 vs 판매 중단"이라는 개념 차이를 몰라도 자연스럽게 올바른 조작으로 유도되는 구조입니다.

REST API와 MCP까지 동일하게 지원

대시보드 UI에만 있으면 SDK로 연동한 고객사나 AI 에이전트는 여전히 구독 있는 요금제를 삭제하려다 막다른 골목에 부딪힙니다. 그래서 판매 중단 기능을 REST API와 MCP 도구까지 동일하게 열어뒀습니다.

POST   /api/v1/plans/{id}/archive   # 판매 중단
DELETE /api/v1/plans/{id}/archive   # 다시 판매하기

MCP를 통해 AI 에이전트에게 "이 요금제 이제 안 팔 거야, 정리해줘"라고 지시해도 동일한 흐름으로 처리됩니다.

직접 설계한다면

  • 삭제 요청이 실패할 수 있는 리소스(다른 테이블이 참조하는 리소스)라면, 삭제와 별개로 "비활성화" 상태를 두는 걸 권장합니다.
  • 삭제 실패 시 원인을 그대로 노출하지 말고, 사용자가 실제로 원했을 법한 대안(비활성화)으로 자동 유도하면 에러 메시지 하나 잘 쓰는 것보다 훨씬 나은 경험을 만듭니다.
  • 이 상태 전환은 대시보드뿐 아니라 API로 연동하는 모든 채널(REST, SDK, AI 에이전트)에 동일하게 노출해야 합니다. 한 채널에만 있으면 다른 채널은 여전히 막다른 골목입니다.

정리

  • 구독자가 있는 요금제는 삭제 대신 "판매 중단"으로 신규 가입만 막고 기존 구독자는 유지하세요.
  • 슈퍼빌링은 이 기능을 대시보드·REST API·MCP 전 채널에서 동일하게 지원합니다. Quickstart 문서에서 확인할 수 있습니다.

3분만에 구독결제 연동해보기

요금제 설계부터 웹훅 등록까지, 슈퍼빌링으로 바로 시작할 수 있습니다.

무료로 시작하기