whop

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Whop Platform Expert

Whop平台专家指南

Whop is a platform for selling digital products, memberships, courses, and community access.
Whop是一个用于销售数字产品、会员服务、课程及社区访问权限的平台。

When to Use

适用场景

  • Building membership/subscription products
  • Integrating Whop checkout and payments
  • Managing courses and educational content
  • Gating content by membership status
  • Handling webhooks for payment events
  • Building Whop apps with OAuth
  • 构建会员/订阅产品
  • 集成Whop结账与支付流程
  • 管理课程及教育内容
  • 根据会员身份限制内容访问
  • 处理支付事件的Webhooks
  • 基于OAuth构建Whop应用

Quick Start

快速入门

Authentication

认证

typescript
const headers = {
  Authorization: `Bearer ${process.env.WHOP_API_KEY}`,
  "Content-Type": "application/json",
};

const response = await fetch("https://api.whop.com/api/v5/me", { headers });
API Key Types:
  • Company API Keys - Your own company data (Dashboard → Settings → API Keys)
  • App API Keys - Multi-tenant apps (Dashboard → Developer → Your App)
typescript
const headers = {
  Authorization: `Bearer ${process.env.WHOP_API_KEY}`,
  "Content-Type": "application/json",
};

const response = await fetch("https://api.whop.com/api/v5/me", { headers });
API密钥类型:
  • 企业API密钥 - 用于访问自身企业数据(控制台 → 设置 → API密钥)
  • 应用API密钥 - 用于多租户应用(控制台 → 开发者 → 你的应用)

Core Operations

核心操作

Create Product

创建产品

typescript
const product = await fetch("https://api.whop.com/api/v5/products", {
  method: "POST",
  headers,
  body: JSON.stringify({
    title: "Premium Membership",
    description: "Access to all content",
    visibility: "visible",
  }),
});
typescript
const product = await fetch("https://api.whop.com/api/v5/products", {
  method: "POST",
  headers,
  body: JSON.stringify({
    title: "Premium Membership",
    description: "Access to all content",
    visibility: "visible",
  }),
});

Create Plan

创建套餐

typescript
const plan = await fetch("https://api.whop.com/api/v5/plans", {
  method: "POST",
  headers,
  body: JSON.stringify({
    product_id: "prod_xxx",
    billing_period: 1,
    billing_period_unit: "month",
    price: 2999, // $29.99 in cents
    currency: "usd",
  }),
});
typescript
const plan = await fetch("https://api.whop.com/api/v5/plans", {
  method: "POST",
  headers,
  body: JSON.stringify({
    product_id: "prod_xxx",
    billing_period: 1,
    billing_period_unit: "month",
    price: 2999, // $29.99 以美分为单位
    currency: "usd",
  }),
});

Create Checkout

创建结账流程

typescript
const checkout = await fetch(
  "https://api.whop.com/api/v5/checkout-configurations",
  {
    method: "POST",
    headers,
    body: JSON.stringify({
      plan_id: "plan_xxx",
      success_url: "https://yourapp.com/success",
      cancel_url: "https://yourapp.com/cancel",
      metadata: { user_id: "123" },
    }),
  }
);

const { url } = await checkout.json();
// Redirect user to url
typescript
const checkout = await fetch(
  "https://api.whop.com/api/v5/checkout-configurations",
  {
    method: "POST",
    headers,
    body: JSON.stringify({
      plan_id: "plan_xxx",
      success_url: "https://yourapp.com/success",
      cancel_url: "https://yourapp.com/cancel",
      metadata: { user_id: "123" },
    }),
  }
);

const { url } = await checkout.json();
// 重定向用户至该url

Membership Management

会员管理

List Memberships

列出会员

typescript
const response = await fetch(
  "https://api.whop.com/api/v5/memberships?valid=true",
  { headers }
);

const { data: memberships } = await response.json();
typescript
const response = await fetch(
  "https://api.whop.com/api/v5/memberships?valid=true",
  { headers }
);

const { data: memberships } = await response.json();

Check User Access

检查用户访问权限

typescript
async function checkAccess(userId: string, productId: string): Promise<boolean> {
  const response = await fetch(
    `https://api.whop.com/api/v5/memberships?user_id=${userId}&product_id=${productId}&valid=true`,
    { headers }
  );

  const { data } = await response.json();
  return data.length > 0;
}
typescript
async function checkAccess(userId: string, productId: string): Promise<boolean> {
  const response = await fetch(
    `https://api.whop.com/api/v5/memberships?user_id=${userId}&product_id=${productId}&valid=true`,
    { headers }
  );

  const { data } = await response.json();
  return data.length > 0;
}

Validate License Key

验证许可证密钥

typescript
async function validateLicense(licenseKey: string): Promise<boolean> {
  const response = await fetch(
    `https://api.whop.com/api/v5/memberships?license_key=${licenseKey}`,
    { headers }
  );

  const { data } = await response.json();
  return data.length > 0 && data[0].valid;
}
typescript
async function validateLicense(licenseKey: string): Promise<boolean> {
  const response = await fetch(
    `https://api.whop.com/api/v5/memberships?license_key=${licenseKey}`,
    { headers }
  );

  const { data } = await response.json();
  return data.length > 0 && data[0].valid;
}

Cancel Membership

取消会员

typescript
await fetch(
  `https://api.whop.com/api/v5/memberships/${membershipId}/cancel`,
  {
    method: "POST",
    headers,
  }
);
typescript
await fetch(
  `https://api.whop.com/api/v5/memberships/${membershipId}/cancel`,
  {
    method: "POST",
    headers,
  }
);

Payments

支付管理

Get Payment

获取支付记录

typescript
const payment = await fetch(
  `https://api.whop.com/api/v5/payments/${paymentId}`,
  { headers }
);
typescript
const payment = await fetch(
  `https://api.whop.com/api/v5/payments/${paymentId}`,
  { headers }
);

Refund Payment

退款

typescript
await fetch(`https://api.whop.com/api/v5/payments/${paymentId}/refund`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    amount: 1000, // Optional: partial refund in cents
  }),
});
typescript
await fetch(`https://api.whop.com/api/v5/payments/${paymentId}/refund`, {
  method: "POST",
  headers,
  body: JSON.stringify({
    amount: 1000, // 可选:部分退款,以美分为单位
  }),
});

Courses

课程管理

Create Course

创建课程

typescript
const course = await fetch("https://api.whop.com/api/v5/courses", {
  method: "POST",
  headers,
  body: JSON.stringify({
    product_id: "prod_xxx",
    title: "Complete Web Development",
    description: "Learn fullstack from scratch",
    visibility: "visible",
  }),
});
typescript
const course = await fetch("https://api.whop.com/api/v5/courses", {
  method: "POST",
  headers,
  body: JSON.stringify({
    product_id: "prod_xxx",
    title: "Complete Web Development",
    description: "Learn fullstack from scratch",
    visibility: "visible",
  }),
});

Create Chapter

创建章节

typescript
const chapter = await fetch("https://api.whop.com/api/v5/course-chapters", {
  method: "POST",
  headers,
  body: JSON.stringify({
    course_id: "course_xxx",
    title: "Introduction to JavaScript",
    order: 1,
  }),
});
typescript
const chapter = await fetch("https://api.whop.com/api/v5/course-chapters", {
  method: "POST",
  headers,
  body: JSON.stringify({
    course_id: "course_xxx",
    title: "Introduction to JavaScript",
    order: 1,
  }),
});

Create Lesson

创建课时

typescript
const lesson = await fetch("https://api.whop.com/api/v5/course-lessons", {
  method: "POST",
  headers,
  body: JSON.stringify({
    chapter_id: "chapter_xxx",
    title: "Variables and Data Types",
    content: "Lesson content in markdown...",
    type: "video", // or 'text', 'quiz', 'assignment'
    video_url: "https://youtube.com/watch?v=...",
    order: 1,
  }),
});
typescript
const lesson = await fetch("https://api.whop.com/api/v5/course-lessons", {
  method: "POST",
  headers,
  body: JSON.stringify({
    chapter_id: "chapter_xxx",
    title: "Variables and Data Types",
    content: "Lesson content in markdown...",
    type: "video", // 或 'text', 'quiz', 'assignment'
    video_url: "https://youtube.com/watch?v=...",
    order: 1,
  }),
});

Mark Lesson Complete

标记课时为已完成

typescript
await fetch(
  `https://api.whop.com/api/v5/course-lessons/${lessonId}/mark-as-completed`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${userAccessToken}`,
    },
  }
);
typescript
await fetch(
  `https://api.whop.com/api/v5/course-lessons/${lessonId}/mark-as-completed`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${userAccessToken}`,
    },
  }
);

Webhooks

Webhooks

Setup Endpoint

设置端点

typescript
import crypto from "crypto";

export async function POST(req: Request) {
  const body = await req.text();
  const signature = req.headers.get("x-whop-signature");

  // Verify signature
  const hash = crypto
    .createHmac("sha256", process.env.WHOP_WEBHOOK_SECRET!)
    .update(body)
    .digest("hex");

  if (hash !== signature) {
    return new Response("Invalid signature", { status: 401 });
  }

  const event = JSON.parse(body);

  switch (event.action) {
    case "payment.succeeded":
      await handlePaymentSuccess(event.data);
      break;

    case "membership.activated":
      await grantAccess(event.data);
      break;

    case "membership.deactivated":
      await revokeAccess(event.data);
      break;

    case "dispute.created":
      await handleDispute(event.data);
      break;
  }

  return Response.json({ received: true });
}
Key webhook events:
EventTrigger
payment.succeeded
Payment completed
payment.failed
Payment failed
membership.activated
Membership started
membership.deactivated
Membership ended
invoice.paid
Recurring payment succeeded
dispute.created
Chargeback initiated
typescript
import crypto from "crypto";

export async function POST(req: Request) {
  const body = await req.text();
  const signature = req.headers.get("x-whop-signature");

  // 验证签名
  const hash = crypto
    .createHmac("sha256", process.env.WHOP_WEBHOOK_SECRET!)
    .update(body)
    .digest("hex");

  if (hash !== signature) {
    return new Response("Invalid signature", { status: 401 });
  }

  const event = JSON.parse(body);

  switch (event.action) {
    case "payment.succeeded":
      await handlePaymentSuccess(event.data);
      break;

    case "membership.activated":
      await grantAccess(event.data);
      break;

    case "membership.deactivated":
      await revokeAccess(event.data);
      break;

    case "dispute.created":
      await handleDispute(event.data);
      break;
  }

  return Response.json({ received: true });
}
关键Webhook事件:
事件触发条件
payment.succeeded
支付完成
payment.failed
支付失败
membership.activated
会员生效
membership.deactivated
会员失效
invoice.paid
定期支付成功
dispute.created
退单申请发起

OAuth Apps

OAuth应用

Redirect to Whop OAuth

重定向至Whop OAuth授权页

typescript
const authUrl = new URL("https://whop.com/oauth");
authUrl.searchParams.set("client_id", process.env.WHOP_CLIENT_ID!);
authUrl.searchParams.set("redirect_uri", "https://yourapp.com/callback");
authUrl.searchParams.set("scope", "memberships:read payments:read");

// Redirect user
window.location.href = authUrl.toString();
typescript
const authUrl = new URL("https://whop.com/oauth");
authUrl.searchParams.set("client_id", process.env.WHOP_CLIENT_ID!);
authUrl.searchParams.set("redirect_uri", "https://yourapp.com/callback");
authUrl.searchParams.set("scope", "memberships:read payments:read");

// 重定向用户
window.location.href = authUrl.toString();

Handle Callback

处理回调

typescript
export async function GET(req: Request) {
  const url = new URL(req.url);
  const code = url.searchParams.get("code");

  const response = await fetch("https://api.whop.com/api/v5/oauth/token", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      client_id: process.env.WHOP_CLIENT_ID!,
      client_secret: process.env.WHOP_CLIENT_SECRET!,
      code,
      grant_type: "authorization_code",
      redirect_uri: "https://yourapp.com/callback",
    }),
  });

  const { access_token, refresh_token } = await response.json();
  // Store tokens securely
}
typescript
export async function GET(req: Request) {
  const url = new URL(req.url);
  const code = url.searchParams.get("code");

  const response = await fetch("https://api.whop.com/api/v5/oauth/token", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      client_id: process.env.WHOP_CLIENT_ID!,
      client_secret: process.env.WHOP_CLIENT_SECRET!,
      code,
      grant_type: "authorization_code",
      redirect_uri: "https://yourapp.com/callback",
    }),
  });

  const { access_token, refresh_token } = await response.json();
  // 安全存储令牌
}

Middleware (Access Control)

中间件(访问控制)

typescript
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export async function middleware(request: NextRequest) {
  const token = request.cookies.get("whop_user_token")?.value;

  if (!token) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  const response = await fetch("https://api.whop.com/api/v5/me/memberships", {
    headers: { Authorization: `Bearer ${token}` },
  });

  const { data } = await response.json();
  const hasAccess = data.some((m: any) => m.status === "active" && m.valid);

  if (!hasAccess) {
    return NextResponse.redirect(new URL("/subscribe", request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/dashboard/:path*", "/premium/:path*"],
};
typescript
// middleware.ts
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";

export async function middleware(request: NextRequest) {
  const token = request.cookies.get("whop_user_token")?.value;

  if (!token) {
    return NextResponse.redirect(new URL("/login", request.url));
  }

  const response = await fetch("https://api.whop.com/api/v5/me/memberships", {
    headers: { Authorization: `Bearer ${token}` },
  });

  const { data } = await response.json();
  const hasAccess = data.some((m: any) => m.status === "active" && m.valid);

  if (!hasAccess) {
    return NextResponse.redirect(new URL("/subscribe", request.url));
  }

  return NextResponse.next();
}

export const config = {
  matcher: ["/dashboard/:path*", "/premium/:path*"],
};

TypeScript Types

TypeScript类型定义

typescript
interface WhopMembership {
  id: string;
  user_id: string;
  product_id: string;
  plan_id: string;
  status: "active" | "paused" | "canceled" | "expired";
  valid: boolean;
  license_key: string;
  renews_at: string | null;
  expires_at: string | null;
  cancel_at_period_end: boolean;
}

interface WhopPayment {
  id: string;
  amount: number;
  currency: string;
  status: "succeeded" | "pending" | "failed";
  user_id: string;
  product_id: string;
}
typescript
interface WhopMembership {
  id: string;
  user_id: string;
  product_id: string;
  plan_id: string;
  status: "active" | "paused" | "canceled" | "expired";
  valid: boolean;
  license_key: string;
  renews_at: string | null;
  expires_at: string | null;
  cancel_at_period_end: boolean;
}

interface WhopPayment {
  id: string;
  amount: number;
  currency: string;
  status: "succeeded" | "pending" | "failed";
  user_id: string;
  product_id: string;
}

Error Handling

错误处理

typescript
async function safeWhopRequest(url: string, options: RequestInit) {
  const response = await fetch(url, options);

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message || "Whop API error");
  }

  return response.json();
}
ErrorMeaning
401 Unauthorized
Invalid API key
403 Forbidden
Insufficient permissions
404 Not Found
Resource doesn't exist
429 Too Many Requests
Rate limited
typescript
async function safeWhopRequest(url: string, options: RequestInit) {
  const response = await fetch(url, options);

  if (!response.ok) {
    const error = await response.json();
    throw new Error(error.message || "Whop API error");
  }

  return response.json();
}
错误含义
401 Unauthorized
API密钥无效
403 Forbidden
权限不足
404 Not Found
资源不存在
429 Too Many Requests
请求频率超限

Security Best Practices

安全最佳实践

DO:
  • Verify webhook signatures
  • Store tokens encrypted
  • Check membership status server-side
  • Use HTTPS everywhere
DON'T:
  • Expose API keys client-side
  • Trust client-sent membership data
  • Skip webhook verification
  • Log sensitive data
建议:
  • 验证Webhook签名
  • 加密存储令牌
  • 服务端校验会员状态
  • 全程使用HTTPS
禁止:
  • 客户端暴露API密钥
  • 信任客户端发送的会员数据
  • 跳过Webhook验证
  • 记录敏感数据

Implementation Checklist

实施检查清单

  • Create Whop account and company
  • Get API keys from Dashboard
  • Set environment variables
  • Create products and plans
  • Implement checkout flow
  • Add membership access checking
  • Set up webhook endpoint
  • Handle payment events
  • Test end-to-end flow
  • 创建Whop账号及企业主体
  • 从控制台获取API密钥
  • 设置环境变量
  • 创建产品及套餐
  • 实现结账流程
  • 添加会员访问权限校验
  • 设置Webhook端点
  • 处理支付事件
  • 端到端流程测试

Resources

资源