본문으로

가이드

레시피: SaaS 구독

암호화폐로 받는 월간·연간 요금제. 기간마다 알림이 붙은 청구서가 가고, 앱은 누가 이용권이 있는지 Perly Pay에 묻습니다.

Markdown으로 열기

암호화폐는 지갑에서 끌어올 수 없으므로 구독은 청구서로 갱신됩니다: 기간이 끝나기 전에 구매자가 다음 청구서를 받고, 결제될 때까지 알림이 갑니다. 자동 청구는 없습니다. 앱이 날짜를 직접 세지 않고 entitlements.check에 묻습니다.

어시스턴트와 함께: 이 레시피는 Perly Pay 플러그인의 sell-subscription 스킬이 내 프로젝트에서 실행합니다. 실행 가능한 예제는 플러그인 저장소의 examples/saas-subscription(MIT)입니다.

작동 방식

  1. 1

    요금제

    model: "subscription"과 recurring.interval(month, year…)이 있는 상품과 가격, 선택으로 체험·유예 기간.

  2. 2

    구독

    사용자를 고객으로 한 이 가격의 청구서가 구독과 첫 청구서를 엽니다. 결제되면 요금제가 활성화됩니다.

  3. 3

    기능 이용권

    entitlements.check({ customer_external_id, product }) → has_access와 ends_at, 서버에서, 방문마다 또는 짧은 캐시와 함께.

  4. 4

    이벤트 듣기

    invoice.fulfilled — 첫 결제와 모든 갱신. subscription.past_due, subscription.unpaid, subscription.ended — 경고하고 닫기 위해.

  5. 5

    구매자의 관리

    고객 포털 링크(portalSessions.create): 열린 갱신 결제, 선결제, 해지.

Subscribe, then gate
const invoice = await pay.invoices.create(
  { line_items: [{ price: PRO_MONTHLY }], customer: customer.id, metadata: { user: userId }, return_url },
  { idempotencyKey: `subscribe-${userId}-${today}` },
);
redirect(invoice.url); // invoice.subscription is the new subscription

const { has_access } = await pay.entitlements.check({ customer_external_id: userId, product: PRO });

유예 기간, 요금제 변경, 상태는 Subscriptions and reminders에 있습니다.

예제 실행

  1. 1

    설치

    examples/saas-subscription에서 npm install(Node 20.12+).

  2. 2

    키

    .env.example을 .env로 복사하고 PERLY_PAY_SECRET_KEY에 테스트 키(sk_test_…)를 넣으세요.

  3. 3

    준비

    npm run setup이 내 키로 상품과 가격을 만들고 .env용 ID를 출력합니다.

  4. 4

    실행

    README에 적힌 대로 npm start(또는 npm run dev).

  5. 5

    지갑 없이 결제

    홈에서 구독하고, 청구서에서 Simulate payment를 누른 뒤 /pro?user=you@example.com을 여세요: 기간이 끝날 때까지 Pro가 열립니다.

함정

  • "지갑에서 자동으로 청구합니다"라고 약속하기. 아무것도 끌어오지 않습니다. "청구서로 갱신됩니다"라고 하세요.
  • 고객 이메일이 없거나 지어낸 것: 갱신 청구서와 알림이 그리로 갑니다.
  • 1분만 늦어도 이용권 닫기. past_due(유예 기간 안)가 무엇을 뜻할지 정하세요.
  • 구매자가 결제에서 돌아왔을 때 이용권을 여는 것. '결제됨'은 검증된 invoice.fulfilled 웹훅이나 내 서버의 entitlements.check만 뜻합니다.