Skip to main content

Server side implementation

To use the embedded component, you need to generate an access token for the connected account’s company. This token grants temporary access to the payout portal for that specific company.
// app/api/token/route.ts
import Whop from "@whop/sdk";
import type { NextRequest } from "next/server";

const whop = new Whop({
  apiKey: process.env.WHOP_API_KEY,
});

export async function GET(request: NextRequest) {
  // Authenticate your user here
  const companyId = request.nextUrl.searchParams.get("companyId");

  if (!companyId) {
    return new Response(null, { status: 400 });
  }
  const tokenResponse = await whop.accessTokens
    .create({
      company_id: companyId,
    })
    .catch(() => {
      return null;
    });
  if (!tokenResponse) {
    return new Response(null, { status: 500 });
  }
  const token = tokenResponse.token;
  return Response.json({
    token,
  });
}

Create Access Token API

See the full API reference for generating access tokens and all available parameters

Client side setup

npm install @whop/embedded-components-react-js @whop/embedded-components-vanilla-js

Client side implementation

import type { WhopElementsOptions } from "@whop/embedded-components-vanilla-js/types";

import {
  BalanceElement,
  Elements,
  PayoutsSession,
  WithdrawButtonElement,
  WithdrawalsElement,
} from "@whop/embedded-components-react-js";
import { loadWhopElements } from "@whop/embedded-components-vanilla-js";

const elements = loadWhopElements();

const appearance: WhopElementsOptions["appearance"] = {
  classes: {
    ".Button": { height: "40px", "border-radius": "8px" },
    ".Button:disabled": { "background-color": "gray" },
    ".Container": { "border-radius": "12px" },
  },
};

export function BalancePage({ companyId }: { companyId: string }) {
  return (
    <Elements appearance={appearance} elements={elements}>
      <PayoutsSession
        token={() =>
          fetch(`/api/token?companyId=${companyId}`)
            .then((res) => res.json())
            .then((data) => data.token)
        }
        companyId={companyId}
        redirectUrl="https://yourapp.com/verification-complete"
      >
        <section
          style={{ display: "flex", flexDirection: "column", gap: "8px" }}
        >
          <div
            style={{ height: "95.5px", width: "100%", position: "relative" }}
          >
            <BalanceElement fallback={<div>Loading...</div>} />
          </div>
          <div style={{ height: "40px", width: "100%", position: "relative" }}>
            <WithdrawButtonElement fallback={<div>Loading...</div>} />
          </div>
          <WithdrawalsElement fallback={<div>Loading...</div>} />
        </section>
      </PayoutsSession>
    </Elements>
  );
}

PayoutsSession Props

The PayoutsSession component requires the following props:
PropTypeRequiredDescription
tokenstring | Promise | FunctionYesAccess token for the session. Can be a string, promise, or function that returns a token.
companyIdstringYesThe company ID for the connected account.
redirectUrlstringYesAbsolute URL (e.g., https://yourapp.com/verification-complete) to redirect the user to after identity verification is completed.
currencystringNoCurrency code (e.g., “USD”). Defaults to “USD”.
The redirectUrl must be a publicly accessible URL. Localhost URLs (e.g., http://localhost:3000) will not work. For local development, use a tunneling service like ngrok to expose your local server.
You can programmatically open modals using the usePayoutsSessionRef hook:
import { usePayoutsSessionRef } from "@whop/embedded-components-react-js";

const sessionRef = usePayoutsSessionRef();

<button
  onClick={() =>
    sessionRef.current?.payoutsSession?.showChangeAccountCountryModal(
      (modal) => ({
        onClose: (ev) => {
          ev.preventDefault();
          modal.close();
        },
      })
    )
  }
>
  Change Account Country
</button>;

Available modals

MethodDescription
showChangeAccountCountryModalAllow users to change their payout account country
showResetAccountModalAllow users to reset their payout account

Hosted payout portal

Instead of embedding the payout portal in your app, you can redirect users to a Whop-hosted payout portal. This is useful when you don’t want to build a custom UI or need a quick integration. Create an account link and redirect the user to the returned URL:
import Whop from "@whop/sdk";

const client = new Whop({
  apiKey: "Company API Key",
});

const accountLink = await client.accountLinks.create({
  company_id: "biz_xxxxxxxxxxxxx",
  use_case: "payouts_portal",
  return_url: "https://yourapp.com/payouts/complete",
  refresh_url: "https://yourapp.com/payouts/refresh",
});

// Redirect the user to the hosted portal
console.log(accountLink.url);
In this example:
  • company_id is the platform or connected account
  • use_case specifies the portal type
  • return_url is where the user is redirected when they want to return to your site
  • refresh_url is where the user is redirected if the session expires

Available use cases

Use caseDescription
account_onboardingKYC and identity verification
payouts_portalWithdrawals, payout methods, KYC, and identity verification
After creating the account link, redirect the user to the url returned in the response. The user will complete the payout flow on the Whop-hosted portal and be redirected back to your return_url when finished.