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

"use client";

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

import {
  BalanceElement,
  Elements,
  PayoutsSession,
  WithdrawButtonElement,
} 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>
        </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”.

Example

<PayoutsSession
  token={() => fetchToken()}
  companyId="biz_abc123"
  redirectUrl="https://yourapp.com/verification-complete"
>
  <BalanceElement fallback={<div>Loading...</div>} />
  <WithdrawButtonElement fallback={<div>Loading...</div>} />
</PayoutsSession>
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.