Whop in Your App
API keys, checkout from code, access checks and webhooks with the Whop SDK

Buzz presents
API keys, checkout links from code, access checks and webhooks, all with the Whop SDK!! we take it slow, promiss.API keys, checkout links from code, access checks and webhooks, all with the Whop SDK!! we take it slow, promiss.

Whop works fine without code, but it also has an API for developers. This lesson covers the four things you'll touch the MOST. API keys, creating a checkout from code, checking who has access, and receiving webhooks. Deep breath... we'll take them one at a time.
The Big Picture#
Here's how a Whop sale usually flows when you've got your own app.
Step 1. Your server creates a checkout#
Your server asks Whop for a checkout page and gets back a URL.
Step 2. The buyer pays on Whop#
The buyer opens that URL and pays. Card details go to Whop and never touch your server.
Step 3. Whop sends a webhook#
Whop sends your server a message saying the payment succeeded.
Step 4. Your app gives access#
Your server marks the order paid and lets the buyer in. Later on, your app can ask Whop whether someone still has access.
Sound like the Stripe flow? Yep, pretty much. The difference is that Whop also stores memberships, so it can answer the "does this person have access?" question for you.
API Keys#
An API key is a secret password that lets your server talk to Whop's API. Whop has a few kinds of credentials, and most projects start with an Account API key, which lets your server act for your own business.
To make one, open your Whop dashboard and head to the developer section. Under Account API Keys, select Create, give the key a name you'll recognize, and pick its permissions. Copy the key when Whop shows it and save it in your .env file.
WHOP_API_KEY=whop_xxxxxxxxxxxxxxxxxWhop also suggests the Admin role for your first test only. Once you know which endpoints you actually use, switch the key to a narrower custom set of permissions.
Install the SDK#
An SDK is a library that wraps the API, so you call functions instead of building web requests by hand. Whop's TypeScript SDK is the @whop/sdk package.
npm install @whop/sdkWhop also publishes SDKs for Python (whop-sdk) and Ruby (whop_sdk).
Now make your first call. This one asks Whop "which business does this key belong to?" If it prints an ID starting with biz_, your key works. Easy win.
import { WhopClient } from "@whop/sdk";
const apiKey = process.env.WHOP_API_KEY;
if (!apiKey) {
throw new Error("Set WHOP_API_KEY");
}
const client = new WhopClient({
token: apiKey,
});
const account = await client.accounts.me();
console.log(account.id);Save that as first-call.mts (the .mts ending lets you use await at the top of the file) and run it with npx tsx --env-file=.env first-call.mts. The --env-file part loads your key from .env.
Create a Checkout From Code#
Last lesson you made a checkout link by clicking around the dashboard. Your server can do the same thing with ONE call. It hands back a purchase_url, which is a live payment page.
const checkout = await client.checkoutConfigurations.create({
plan: {
title: "Starter",
plan_type: "one_time",
initial_price: 10.0,
currency: "usd",
},
});
console.log(checkout.purchase_url);This example creates a new one-time price on the fly. Already made a plan in the dashboard? Pass its ID as plan_id instead of the plan object. You can't send both.
Send the buyer to purchase_url with a link or a redirect. Whop takes the payment page from there.
Sandbox keys only work against the sandbox, so you have to tell the SDK which one you mean. The SDK exports WhopEnvironment, and you pass environment: WhopEnvironment.Sandbox next to token when you create the client.
Whop also has ways to put checkout right on your own page instead of linking out. Its Accept Payments guide compares them. A shared checkout link is still the simplest place to start.
Check Who Has Access#

Here's where Whop saves you a pile of work. When someone pays, Whop creates a membership for them. Your app can just ask Whop whether a user has access to something, instead of tracking it all in your own database.
The method is users.checkAccess. You pass in a user ID (starts with user_) and the ID of the thing you're checking.
const response = await client.users.checkAccess({
id: "user_xxxxxxxxxxxxx",
resource_id: "prod_xxxxxxxxxxxxx",
});
console.log(response.has_access);
console.log(response.access_level);The resource_id can point at three kinds of things.
| ID starts with | Checks access to |
|---|---|
biz_ | Your whole business |
prod_ | One product |
exp_ | One experience, like a course or chat |
The answer comes back as has_access (true or false) plus an access_level.
| Access level | Meaning |
|---|---|
customer | The user has a valid membership |
admin | The user is on the business's team |
no_access | The user has no access |
There's one catch... you need the user's Whop ID in the first place. Apps that run inside Whop get it from a token Whop sends with each request. Apps that run on their own site can use "Sign in with Whop", which is Whop's OAuth flow. Both get covered in Whop's Authentication and Auth and API Keys guides.
Webhooks#
A webhook is a message Whop sends to your server when something happens, like payment.succeeded or membership.activated. Same deal as Stripe, this is how you find out what really happened.
To set one up, open the developer section of your dashboard and select Create webhook. Paste your server's HTTPS address, keep the API version on v1, and pick the events you want. Whop gives you a signing secret that starts with ws_. Store it EXACTLY as given.
WHOP_WEBHOOK_SECRET=ws_your_secret_hereHere's the Next.js example from Whop's Webhooks guide, with one small tweak. It checks the signature, reads the event type and answers fast. Put it in app/api/webhooks/whop/route.ts and install the helper it uses with npm install @vercel/functions.
// app/api/webhooks/whop/route.ts
import { waitUntil } from "@vercel/functions";
import { unwrapWebhook } from "@whop/sdk/helpers";
import type { NextRequest } from "next/server";
// The shape of the events this route reads
type WhopEvent = { type: string; data: Record<string, unknown> };
export async function POST(request: NextRequest): Promise<Response> {
// Give the raw body. Parsing it first changes the bytes and the signature check fails.
const payload = await request.text();
const headers = Object.fromEntries(request.headers);
const event = unwrapWebhook<WhopEvent>(payload, {
headers,
key: process.env.WHOP_WEBHOOK_SECRET!,
});
if (event.type === "payment.succeeded") {
waitUntil(handlePaymentSucceeded(event.data));
}
// Respond in less than 5 seconds, or Whop retries.
return new Response("OK", { status: 200 });
}
async function handlePaymentSucceeded(payment: Record<string, unknown>) {
// Do the fulfillment work here: update your database, give access, send email.
console.log("[PAYMENT SUCCEEDED]", payment);
}The tweak is that <WhopEvent> part. It tells TypeScript what an event looks like. Leave it off and TypeScript can't tell that event.data is an object, so the build fails with a type error.
A few rules from Whop's docs are worth tattooing somewhere.
- Verify first.
unwrapWebhookthrows if the signature is wrong, so fake requests never reach your code. - Answer within 5 seconds. Do the slow stuff in the background. That's what
waitUntildoes on Vercel. - Expect repeats. Whop can send the same event more than once. Save each
webhook-idheader and skip the ones you've already handled. - Don't trust the order. A newer event can arrive before an older one.
- Use a public URL. Whop rejects
localhost, so use a tunnel like ngrok while developing.
TL;DR#
- An Account API key lets your server act for your business, and it must stay on the server
- The TypeScript SDK is
@whop/sdk, andclient.accounts.me()is a good first test client.checkoutConfigurations.create()returns apurchase_urlbuyers can pay atclient.users.checkAccess()asks Whop whether a user has access to a business, product or experience- Webhooks such as
payment.succeededtell your server what really happened, so give access there - Build in the sandbox first, because checkout links in your normal account charge real money
What's Next?#
Try the whole loop in the sandbox. Create a key, make a checkout, pay with the test card and watch your webhook fire. That first webhook landing is a weirdly great feeling...
This lesson ends with 2 short activities.
