SaaS 결제의 어려움
개인 개발자가 SaaS 제품을 만들 때 가장 골치 아픈 부분이 결제 시스템입니다. Stripe를 직접 연동하려면 웹훅 처리, 구독 관리, 인보이스 생성 등 신경 쓸 것이 한두 가지가 아닙니다. 여기에 해외 판매 시 VAT, GST 같은 세금 처리까지 더해지면 결제 시스템 하나에 몇 주를 소비하게 됩니다.
Polar.sh는 이런 문제를 해결하기 위해 만들어진 개발자 중심의 결제 플랫폼입니다. Merchant of Record(MoR) 모델을 채택해서 세금 계산, 징수, 납부를 모두 대행합니다. 개발자는 제품 개발에만 집중할 수 있습니다.
Polar.sh의 핵심 특징
Merchant of Record
Polar가 판매자 역할을 대행합니다. 고객이 결제하면 Polar가 세금을 처리하고, 개발자에게 정산금을 지급합니다. 한국에서 미국이나 유럽 고객에게 판매할 때 각 국가의 세법을 신경 쓸 필요가 없습니다.
유연한 가격 모델
일회성 구매, 월간·연간 구독, 사용량 기반 과금을 모두 지원합니다. 무료 체험 기간 설정, 요금제 업그레이드·다운그레이드 시 자동 안분 계산까지 처리됩니다.
자동화된 혜택 전달
결제 완료 시 라이선스 키 발급, 파일 다운로드 링크 제공, GitHub 저장소 접근 권한 부여, Discord 역할 할당 등을 자동으로 처리합니다. 수동으로 이메일을 보내거나 권한을 설정할 필요가 없습니다.
합리적인 수수료
거래당 4% + $0.40의 수수료를 부과합니다. 월 고정 비용이나 셋업 비용이 없어서 매출이 없으면 비용도 없습니다. Gumroad(10%)이나 Lemon Squeezy(5% + 50¢)보다 저렴합니다.
Next.js에서 Polar.sh 연동하기
계정 설정
Polar.sh에 가입한 후 Organization을 생성하고, Product를 만듭니다. 대시보드에서 API 키를 발급받으세요.
SDK 설치
npm install @polar-sh/sdk
환경 변수 설정
POLAR_ACCESS_TOKEN=your_access_token
POLAR_ORGANIZATION_ID=your_org_id
POLAR_WEBHOOK_SECRET=your_webhook_secret
제품 목록 가져오기
서버 컴포넌트에서 제품 정보를 불러와 가격 페이지에 표시할 수 있습니다.
import { Polar } from "@polar-sh/sdk";
const polar = new Polar({
accessToken: process.env.POLAR_ACCESS_TOKEN,
});
export async function getProducts() {
const result = await polar.products.list({
organizationId: process.env.POLAR_ORGANIZATION_ID,
isArchived: false,
});
return result.result.items;
}
체크아웃 세션 생성
사용자가 구매 버튼을 클릭하면 체크아웃 세션을 생성하고 결제 페이지로 리다이렉트합니다.
import { NextResponse } from "next/server";
import { Polar } from "@polar-sh/sdk";
const polar = new Polar({
accessToken: process.env.POLAR_ACCESS_TOKEN,
});
export async function POST(request: Request) {
const { productPriceId, customerEmail } = await request.json();
const checkout = await polar.checkouts.create({
productPriceId,
customerEmail,
successUrl: `${process.env.NEXT_PUBLIC_URL}/success`,
});
return NextResponse.json({ url: checkout.url });
}
웹훅 처리
결제 완료, 구독 갱신, 취소 등의 이벤트를 웹훅으로 수신합니다.
import { validateEvent } from "@polar-sh/sdk/webhooks";
export async function POST(request: Request) {
const body = await request.text();
const signature = request.headers.get("webhook-signature");
const event = validateEvent(
body,
{ "webhook-signature": signature },
process.env.POLAR_WEBHOOK_SECRET,
);
switch (event.type) {
case "subscription.created":
await activateSubscription(event.data);
break;
case "subscription.canceled":
await deactivateSubscription(event.data);
break;
}
return new Response("OK");
}
Polar.sh vs Stripe 직접 연동
Stripe를 직접 연동하면 더 세밀한 제어가 가능하지만, 세금 처리를 직접 해야 합니다. Stripe Tax를 추가하면 수수료가 올라가고, 각 국가별 세금 등록도 직접 해야 합니다.
Polar.sh는 이 모든 것을 대행하므로 인디 개발자나 소규모 팀에게 적합합니다. 매출이 커지고 결제 로직이 복잡해지면 그때 Stripe로 마이그레이션하는 것도 방법입니다.
제품을 빠르게 출시하고 검증하는 단계에서는 결제 인프라에 시간을 쓰는 것보다 Polar.sh 같은 서비스를 활용하는 것이 훨씬 효율적입니다. 결제 시스템은 제품의 핵심이 아니라 제품을 지탱하는 인프라이기 때문입니다.