데브포일 홈
DEV MODE - 실서버 영향 없음 📦 배포 관리
구독 결제 & 자동 갱신
+250 XP
LEVEL 56 QUEST

구독 결제 & 자동 갱신

토스페이먼츠 빌링키, PayPal 구독 플랜, 자동 갱신 크론잡까지 SaaS 핵심 수익 엔진을 구축합니다.

subscriptions 테이블 설계

구독 = SaaS의 수익 엔진

일회성 결제와 달리 구독 결제는 매월 자동으로 수익이 발생합니다. MRR(Monthly Recurring Revenue)은 SaaS의 핵심 지표이며, 구독 시스템은 이를 자동화하는 핵심 엔진입니다.

-- 구독 정보를 관리하는 테이블 CREATE TABLE subscriptions ( id INT AUTO_INCREMENT PRIMARY KEY, user_id INT NOT NULL, plan_id INT NOT NULL, status ENUM('trial', 'active', 'past_due', 'cancelled', 'expired') DEFAULT 'trial', -- 결제 수단 정보 payment_method ENUM('toss', 'paypal') NOT NULL, billing_key VARCHAR(200) NULL, -- 토스 빌링키 paypal_sub_id VARCHAR(100) NULL, -- PayPal 구독 ID -- 금액 정보 amount INT NOT NULL, -- 구독 금액 currency VARCHAR(3) DEFAULT 'KRW', -- 구독 기간 정보 trial_ends_at DATETIME NULL, -- 무료 체험 종료일 current_period_start DATETIME NOT NULL, -- 현재 결제 주기 시작 current_period_end DATETIME NOT NULL, -- 현재 결제 주기 종료 next_billing_date DATETIME NULL, -- 다음 결제일 -- 결제 실패 관리 retry_count TINYINT DEFAULT 0, -- 재시도 횟수 last_retry_at DATETIME NULL, -- 마지막 재시도 시각 -- 취소 정보 cancelled_at DATETIME NULL, cancel_reason VARCHAR(200) NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, INDEX idx_user (user_id), INDEX idx_status (status), INDEX idx_next_billing (next_billing_date), UNIQUE INDEX idx_active_user (user_id, status) );
trial (무료 체험) 가입 후 7~14일간 무료로 서비스를 사용하는 기간. 체험 기간이 끝나면 자동으로 첫 결제가 시도됩니다.
active (활성) 정상적으로 결제가 이루어지고 서비스를 사용 중인 상태. 매월 자동 결제됩니다.
past_due (연체) 결제가 실패하여 재시도 중인 상태. 3회 재시도 후에도 실패하면 계정이 일시정지됩니다.
cancelled (취소) 사용자가 구독을 취소한 상태. 현재 결제 주기가 끝날 때까지는 서비스 이용 가능합니다.

토스페이먼츠 빌링키 발급

빌링키란?

빌링키는 고객의 카드 정보를 대신하는 토큰입니다. 카드번호를 직접 저장하지 않고, 빌링키만 저장하면 언제든 자동 결제를 할 수 있습니다. PCI DSS 규정을 준수하면서 반복 결제가 가능합니다.

<!-- billing_register.php - 카드 등록 (빌링키 발급) 프론트엔드 --> <script src="https://js.tosspayments.com/v1/payment"></script> <button id="register-card">카드 등록하기</button> <script> const tossPayments = TossPayments('test_ck_D5GePWvyJnrK0W0k6q8gLzN97Eoq'); document.getElementById('register-card') .addEventListener('click', async () => { try { await tossPayments.requestBillingAuth('카드', { customerKey: 'USER_', successUrl: 'https://mysite.com/billing/success.php', failUrl: 'https://mysite.com/billing/fail.php', }); } catch (error) { alert('카드 등록 중 오류: ' + error.message); } }); </script>
// billing/success.php - 빌링키 발급 완료 처리 <?php $authKey = $_GET['authKey'] ?? ''; $customerKey = $_GET['customerKey'] ?? ''; $config = require '../config/payment.php'; $secretKey = $config['toss']['secret_key']; // 빌링키 발급 API 호출 $ch = curl_init(); curl_setopt_array($ch, [ CURLOPT_URL => "https://api.tosspayments.com/v1/billing/authorizations/issue", CURLOPT_POST => true, CURLOPT_RETURNTRANSFER => true, CURLOPT_HTTPHEADER => [ 'Authorization: Basic ' . base64_encode($secretKey . ':'), 'Content-Type: application/json', ], CURLOPT_POSTFIELDS => json_encode([ 'authKey' => $authKey, 'customerKey' => $customerKey, ]), ]); $response = json_decode(curl_exec($ch), true); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); curl_close($ch); if ($httpCode === 200) { $billingKey = $response['billingKey']; $cardCompany = $response['card']['company'] ?? ''; $cardNumber = $response['card']['number'] ?? ''; // 빌링키를 구독 테이블에 저장 $stmt = $pdo->prepare(" INSERT INTO subscriptions (user_id, plan_id, status, payment_method, billing_key, amount, current_period_start, current_period_end, next_billing_date, trial_ends_at) VALUES (?, ?, 'trial', 'toss', ?, ?, NOW(), DATE_ADD(NOW(), INTERVAL 7 DAY), DATE_ADD(NOW(), INTERVAL 7 DAY), DATE_ADD(NOW(), INTERVAL 7 DAY)) "); $stmt->execute([ $_SESSION['user_id'], $planId, $billingKey, $planAmount, ]); header('Location: /subscription/registered.php'); } else { error_log("빌링키 발급 실패: " . json_encode($response)); header('Location: /billing/fail.php'); } ?>
🔒
여기까지는 미리보기입니다
구독 결제 & 자동 갱신
무료 가입하면 이어서 볼 수 있고, 강의를 완료할 때마다 XP와 레벨이 쌓입니다.
Google로 3초 만에 시작 →🧵 Threads로 시작무료 공개 강의 둘러보기 (Lv.1~3)