惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
B
Blog
Stack Overflow Blog
Stack Overflow Blog
量子位
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
T
Tailwind CSS Blog
MongoDB | Blog
MongoDB | Blog
小众软件
小众软件
博客园 - 三生石上(FineUI控件)
Recent Announcements
Recent Announcements
U
Unit 42
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
腾讯CDC
D
DataBreaches.Net
Microsoft Azure Blog
Microsoft Azure Blog
G
Google Developers Blog
M
MIT News - Artificial intelligence
P
Proofpoint News Feed
罗磊的独立博客
L
LangChain Blog
V
Visual Studio Blog
雷峰网
雷峰网
aimingoo的专栏
aimingoo的专栏
宝玉的分享
宝玉的分享

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
How I add Polar (Merchant of Record) + Stripe to any Next...
Cenk KURTOĞLU · 2026-06-22 · via DEV Community

Cenk KURTOĞLU

If you're a solo dev outside the US, "just add Stripe" is rarely just. Stripe doesn't onboard sellers directly in a lot of countries, so you reach for a Merchant of Record (MoR) like Polar or Lemon Squeezy — and then you hit the second wall: the official SDK throws fetch failed the moment you deploy to a serverless platform like Vercel.

I shipped paid checkout on two live products this way and got tired of re-solving the same problems. Here's the pattern that actually works in production.

1. Skip the SDK. Use native fetch.

Most payment SDKs assume a long-lived Node server. On serverless, the bundled HTTP client and keep-alive sockets misbehave and you get opaque fetch failed errors. The fix is boring and bulletproof: call the REST API directly.

// lib/polar.ts
const POLAR_API = "https://api.polar.sh/v1";

export async function createCheckout(productId: string, successUrl: string) {
  const res = await fetch(`${POLAR_API}/checkouts/`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.POLAR_ACCESS_TOKEN!}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ products: [productId], success_url: successUrl }),
  });
  if (!res.ok) throw new Error(`Polar checkout failed: ${res.status}`);
  return res.json();
}

No SDK, no version drift, no serverless surprises. Works on Vercel, Cloudflare, anywhere fetch exists.

2. Verify webhooks yourself (it's ~15 lines)

Don't trust a payment callback you didn't sign-check. Polar uses the Standard Webhooks spec (base64 HMAC); Stripe uses its own t=,v1= scheme. Both are a crypto.timingSafeEqual away:

// lib/verify.ts
import crypto from "node:crypto";

export function verifyPolar(payload: string, signature: string, secret: string) {
  const expected = crypto
    .createHmac("sha256", Buffer.from(secret, "base64"))
    .update(payload)
    .digest("base64");
  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}

timingSafeEqual (not ===) is the part people skip — and it's exactly the part that matters for a signature check.

3. Verify payment status server-side on the success page

The redirect to your success_url is not proof of payment — a user can just visit that URL. Re-fetch the checkout server-side before you grant access or trigger a download:

const checkout = await getCheckout(checkoutId);
const PAID = ["succeeded", "confirmed"];
if (!PAID.includes(checkout.status)) redirect("/pricing");

4. One source of truth for tiers

Keep your subscription tiers in one typed object and generate the pricing UI from it. Adding a plan becomes a one-line change, not a five-file hunt.

export const TIERS = {
  pro:      { name: "Pro",      price: 19, productId: process.env.POLAR_PRO_ID! },
  business: { name: "Business", price: 49, productId: process.env.POLAR_BIZ_ID! },
} as const;

Why this matters

This is the unglamorous 20% of payments that eats 80% of the time: serverless fetch failures, signature verification, the success-page trust gap. None of it is hard once you've seen it — but the first time costs you a weekend.

I packaged the full working version — checkout, signed webhooks for both Polar and Stripe, tiers, and a server-verified success page — as a drop-in Next.js kit so you don't have to re-derive it. It's the exact code running on my own live products: Polar + Stripe Kit for Next.js.

Either way, the four patterns above are yours to copy. Ship the payment, not the yak-shave.


Note for non-US devs: if you can't onboard to Stripe directly, a Merchant of Record like Polar becomes the seller of record, handles tax/VAT, and pays you out. The code above covers both paths.