OPEN HYPER STEP
← 목록으로 (수익화)
MONETIZATION · 41 / 69
monetization
CHAPTER 41 / 69
읽기 약 2
FUNCTION

구독 결제 연동: Stripe


핵심 개념

Next.js + Stripe로 글로벌 구독 결제를 구현한다 — Checkout Session부터 웹훅까지.

본문

Stripe 설정

BASH📋 코드 (1줄)
npm install stripe @stripe/stripe-js

.env.local:

📋 코드 (3줄)
STRIPE_SECRET_KEY=sk_test_...
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...

1. Checkout Session 생성 (서버)

TYPESCRIPT📋 코드 (25줄)
// app/api/checkout/route.ts
import Stripe from 'stripe';
import { NextRequest, NextResponse } from 'next/server';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function POST(req: NextRequest) {
  const { priceId, userId } = await req.json();

  const session = await stripe.checkout.sessions.create({
    mode: 'subscription',
    payment_method_types: ['card'],
    line_items: [{ price: priceId, quantity: 1 }],
    success_url: `${process.env.NEXT_PUBLIC_URL}/dashboard?success=true`,
    cancel_url: `${process.env.NEXT_PUBLIC_URL}/pricing?canceled=true`,
    customer_email: undefined,
    metadata: { userId },
    // 한국 결제 추가 (Stripe Korea)
    payment_method_options: {
      card: { request_three_d_secure: 'any' },
    },
  });

  return NextResponse.json({ url: session.url });
}

2. 결제 버튼 (클라이언트)

TYPESCRIPT📋 코드 (17줄)
'use client';
import { loadStripe } from '@stripe/stripe-js';

const stripePromise = loadStripe(process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!);

export function SubscribeButton({ priceId }: { priceId: string }) {
  const handleClick = async () => {
    const res = await fetch('/api/checkout', {
      method: 'POST',
      body: JSON.stringify({ priceId, userId: 'current-user-id' }),
    });
    const { url } = await res.json();
    window.location.href = url;  // Stripe Checkout으로 리다이렉트
  };

  return <button onClick={handleClick}>구독하기</button>;
}

3. 웹훅 — 결제 확인

TYPESCRIPT📋 코드 (38줄)
// app/api/webhooks/stripe/route.ts
import Stripe from 'stripe';
import { headers } from 'next/headers';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);

export async function POST(req: Request) {
  const body = await req.text();
  const sig = (await headers()).get('stripe-signature')!;

  let event: Stripe.Event;
  try {
    event = stripe.webhooks.constructEvent(body, sig, process.env.STRIPE_WEBHOOK_SECRET!);
  } catch (err) {
    return new Response('Webhook signature verification failed', { status: 400 });
  }

  switch (event.type) {
    case 'checkout.session.completed': {
      const session = event.data.object;
      // 사용자 DB에 구독 활성화 표시
      await activateSubscription(session.metadata!.userId, session.subscription as string);
      break;
    }
    case 'customer.subscription.deleted': {
      const sub = event.data.object;
      await deactivateSubscription(sub.id);
      break;
    }
    case 'invoice.payment_failed': {
      // 결제 실패 → 사용자에게 이메일
      await sendPaymentFailedEmail(event.data.object.customer_email!);
      break;
    }
  }

  return new Response('ok', { status: 200 });
}

4. 구독 관리 (업/다운그레이드/해지)

TYPESCRIPT📋 코드 (15줄)
// 플랜 변경
async function changePlan(subscriptionId: string, newPriceId: string) {
  const subscription = await stripe.subscriptions.retrieve(subscriptionId);
  await stripe.subscriptions.update(subscriptionId, {
    items: [{ id: subscription.items.data[0].id, price: newPriceId }],
    proration_behavior: 'create_prorations',  // 비율 정산
  });
}

// 해지 (다음 결제일까지 유지)
async function cancelAtPeriodEnd(subscriptionId: string) {
  await stripe.subscriptions.update(subscriptionId, {
    cancel_at_period_end: true,
  });
}

⚠️ 프로덕션 체크리스트

  • ✅ 웹훅 시크릿 검증
  • ✅ Idempotency Key — 중복 요청 방지
  • ✅ 테스트 모드 카드 (4242...) → 라이브 전환 시 키 교체
  • ✅ Stripe Radar — 사기 거래 자동 차단

AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude

무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6

내 Stripe 통합 코드의
웹훅 검증·idempotency·에러 핸들링을 분석하고
프로덕션 수준으로 개선해줘.
ChatGPT

무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro

Stripe + Next.js 14 App Router로
구독 결제 + 무료 체험 + 다운그레이드를 구현한
완성 코드(서버+클라이언트)를 보여줘.
Gemini

무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro

내 Stripe 대시보드 데이터를 분석해서
결제 실패율·해지 패턴·MRR 변화를
종합 리포트로 만들어줘.
Grok

무료: Grok 4.1 / SuperGrok $30/mo

2026년 한국 1인 SaaS — Stripe(글로벌) vs 토스페이먼츠(국내)
실무 채택 트렌드와 비용 차이를 솔직히 알려줘.

⭐ 이것만 기억하세요
구독 결제 연동: Stripe 이 3가지만 확실히 잡으세요
1.Stripe Checkout Session으로 PCI-DSS 부담 없이 글로벌 결제를 구현할 수 있다
2.웹훅으로 결제 상태를 비동기 동기화하면 결제-DB 불일치 사고를 막을 수 있다
3.다음 챕터에서 한국 시장 특화 결제 — 토스페이먼츠를 다룬다


공유하기
진행도 41 / 69