---
title: "Stripe Marketplace App"
description: "The Stripe Marketplace App integration bridges Stripe payments and Dub's partner program infrastructure, automating conversion tracking and partner commission generation. By packaging extension def..."
last_updated: "2026-10-05T05:07:35.154101+00:00"
canonical_url: "https://www.doc0.dev/docs/934e554a-e6a1-476f-bb2f-23e62d86c3fd/technical/external-integrations/stripe-marketplace-app"
---

<details>
<summary>Relevant source files</summary>

The following files were used as context for generating this wiki page:

- [packages/stripe-app/stripe-app.json](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/stripe-app.json)
- [apps/web/scripts/dev/data.json](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json)
- [packages/hubspot-app/src/app/app-hsmeta.json](https://github.com/blade47/dub/blob/HEAD/packages/hubspot-app/src/app/app-hsmeta.json)
- [apps/web/app/app.dub.co/dashboard/slug/ee/settings/integrations/integrationSlug/page-client.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/settings/integrations/%5BintegrationSlug%5D/page-client.tsx)
- [packages/stripe-app/src/views/AppSettings.tsx](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx)
- [apps/web/app/ee/app.dub.co/embed/referrals/page-client.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/app.dub.co/embed/referrals/page-client.tsx)
- [packages/stripe-app/src/utils/constants.ts](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/utils/constants.ts)
- [apps/web/ui/layout/sidebar/app-sidebar-nav.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/ui/layout/sidebar/app-sidebar-nav.tsx)
- [apps/web/app/ee/partners.dub.co/dashboard/programs/programSlug/enrolled/analytics/page.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/%5BprogramSlug%5D/(enrolled)/analytics/page.tsx)
- [apps/web/app/ee/admin.dub.co/dashboard/components/user-info.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/admin.dub.co/(dashboard)/components/user-info.tsx)
- [apps/web/app/ee/app.dub.co/embed/referrals/earnings-summary.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/app.dub.co/embed/referrals/earnings-summary.tsx)
- [apps/web/app/ee/app.dub.co/embed/referrals/page.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/app.dub.co/embed/referrals/page.tsx)
- [apps/web/app/app.dub.co/dashboard/slug/ee/program/analytics/program-analytics-shell.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/program/analytics/program-analytics-shell.tsx)
- [apps/web/app/app.dub.co/dashboard/slug/ee/settings/tracking/page.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/settings/tracking/page.tsx)
- [apps/web/app/ee/app.dub.co/embed/referrals/quickstart.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/app.dub.co/embed/referrals/quickstart.tsx)
- [apps/web/app/ee/app.dub.co/embed/referrals/activity.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/app.dub.co/embed/referrals/activity.tsx)
- [packages/hubspot-app/src/app/webhooks/webhooks-hsmeta.json](https://github.com/blade47/dub/blob/HEAD/packages/hubspot-app/src/app/webhooks/webhooks-hsmeta.json)
- [apps/web/app/ee/app.dub.co/embed/referrals/resources.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/app.dub.co/embed/referrals/resources.tsx)
- [apps/web/app/app.dub.co/dashboard/slug/ee/settings/billing/page.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/settings/billing/page.tsx)
- [apps/web/app/app.dub.co/dashboard/slug/ee/settings/page.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/settings/page.tsx)
- [apps/web/app/ee/partners.dub.co/dashboard/programs/programSlug/enrolled/earnings/page.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/%5BprogramSlug%5D/(enrolled)/earnings/page.tsx)
- [packages/stripe-app/src/hooks/use-workspace.ts](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/hooks/use-workspace.ts)
- [apps/web/app/app.dub.co/dashboard/slug/ee/settings/tracking/installation-section.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/settings/tracking/installation-section.tsx)
- [apps/web/ui/guides/install-stripe-integration-button.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/ui/guides/install-stripe-integration-button.tsx)
- [apps/web/app/app.dub.co/marketplace/...segments/page.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/marketplace/%5B%5B...segments%5D%5D/page.tsx)
- [apps/web/app/ee/partners.dub.co/dashboard/programs/programSlug/enrolled/events/page.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/partners.dub.co/(dashboard)/programs/%5BprogramSlug%5D/(enrolled)/events/page.tsx)
- [apps/web/ui/analytics/index.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/ui/analytics/index.tsx)
- [apps/web/app/ee/admin.dub.co/dashboard/programs/marketplace/page.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/admin.dub.co/(dashboard)/programs/marketplace/page.tsx)
- [apps/web/app/ee/app.dub.co/embed/referrals/token.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/(ee)/app.dub.co/embed/referrals/token.tsx)
- [apps/web/app/app.dub.co/marketplace/layout.tsx](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/marketplace/layout.tsx)
</details>

## Overview

The Stripe Marketplace App integration bridges Stripe payments and Dub's partner program infrastructure, automating conversion tracking and partner commission generation. By packaging extension definitions, secure OAuth authentication flows, workspace context hooks, and native settings controls into a unified Stripe App manifest, it enables merchants to seamlessly connect their Stripe accounts with Dub workspaces. This integration solves the complexity of attribution across payment boundaries, ensuring that checkout events, invoices, and subscriptions correctly trigger affiliate rewards without manual reconciliation. Sources: [packages/stripe-app/stripe-app.json:1-90](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/stripe-app.json#L1-L90), [apps/web/scripts/dev/data.json:277-297](https://github.com/blade47/dub/blob/HEAD/apps/web/scripts/dev/data.json#L277-L297), [packages/stripe-app/src/views/AppSettings.tsx:1-200](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L1-L200)

## Package Architecture and App Manifest

### Overview

The Stripe App manifest configuration defines the structural integration between the Dub Partners application and the Stripe Marketplace ecosystem. Controlled by `packages/stripe-app/stripe-app.json` against the official Stripe App schema, the application identifies as `dub.co` under the display name `Dub Partners` at version `0.0.25`. Distribution is configured as public with sandbox installation compatibility enabled, utilizing OAuth as the Stripe API access type. Sources: [packages/stripe-app/stripe-app.json:1-91](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/stripe-app.json#L1-L91)

### UI Extension and SDK View Declarations

The UI extension block establishes the view mount points and security policies required for rendering settings controls inside the Stripe dashboard. A single view is declared for the `settings` viewport, loading the `AppSettings` component. Content security policy settings explicitly whitelist OAuth and integration endpoints for connection requests. Sources: [packages/stripe-app/stripe-app.json:7-21](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/stripe-app.json#L7-L21)

| Viewport | Component | Purpose | Sources |
| :--- | :--- | :--- | :--- |
| `settings` | `AppSettings` | Renders configuration controls within the Stripe settings viewport | [packages/stripe-app/stripe-app.json:9-12](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/stripe-app.json#L9-L12) |

> [!NOTE]
> The content security policy restricts `connect-src` directives strictly to `https://api.dub.co/oauth/` and `https://api.dub.co/stripe/integration`, ensuring all external API calls remain bound to authorized Dub domains. Sources: [packages/stripe-app/stripe-app.json:14-20](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/stripe-app.json#L14-L20)

### Host Constants and Permissions Schema

The manifest requires an extensive permissions array covering customer, subscription, invoice, charge, checkout session, user email, connected account, webhook, event, secret, coupon, and promotion code scopes. Alongside these permissions, the app configures allowed redirect URIs and post-install actions. Client configuration constants establish connection endpoints and the Dub client identifier used across runtime integrations. Sources: [packages/stripe-app/stripe-app.json:23-90](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/stripe-app.json#L23-L90), [packages/stripe-app/src/utils/constants.ts:1-6](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/utils/constants.ts#L1-L6)

| Constant Name | Value | Purpose | Sources |
| :--- | :--- | :--- | :--- |
| `DUB_CLIENT_ID` | `dub_app_517290377fe6b4dfcc8726a7061ba9b6da1c4d7d7d75f77a` | Unique Dub application client identifier | [packages/stripe-app/src/utils/constants.ts:2-3](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/utils/constants.ts#L2-L3) |
| `DUB_HOST` | `https://app.dub.co` | Primary Dub web application host URL | [packages/stripe-app/src/utils/constants.ts:4`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/utils/constants.ts#L4) |
| `DUB_API_HOST` | `https://api.dub.co` | Core Dub API server base URL | [packages/stripe-app/src/utils/constants.ts:5`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/utils/constants.ts#L5) |

> [!CAUTION]
> Modifying `allowed_redirect_uris` or altering the `connect-src` CSP block without updating the corresponding backend routes at `https://app.dub.co/api/stripe/integration/callback` will break the OAuth authorization exchange. Sources: [packages/stripe-app/stripe-app.json:14-20](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/stripe-app.json#L14-L20), [packages/stripe-app/stripe-app.json:85-87](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/stripe-app.json#L85-L87)

## OAuth Handshake and Authentication Lifecycle

### Overview

The OAuth handshake and authentication lifecycle manages user authorization between the Stripe App and the Dub platform. This subsystem initializes cryptographic state parameters, exchanges authorization codes for authentication tokens, and validates active sessions against the Dub API. Sources: [packages/stripe-app/src/views/AppSettings.tsx:24-142](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L24-L142)

### Connection Call-Chain Execution Walkthrough

When an unauthenticated user loads the application settings view without an active workspace, the runtime executes a precise initialization and authentication sequence. Sources: [packages/stripe-app/src/views/AppSettings.tsx:121-141](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L121-L141)

1. `useEffect` evaluates the initial component state: if `workspace` is absent and no `code` or `verifier` parameters are present in the `oauthContext`, it invokes `createOAuthState()` from `@stripe/ui-extension-sdk/oauth`. Sources: [packages/stripe-app/src/views/AppSettings.tsx:121-139](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L121-L139)
2. `createOAuthState()` resolves with an `state` string and a cryptographic `challenge`, which are stored via `setOAuthState` and `setChallenge`. Sources: [packages/stripe-app/src/views/AppSettings.tsx:30-31](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L30-31), [packages/stripe-app/src/views/AppSettings.tsx:135-138](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L135-L138)
3. The user interacts with the `SignInView` component, whose primary action triggers `getOAuthUrl({ state, challenge, mode })` using the generated parameters. Sources: [packages/stripe-app/src/views/AppSettings.tsx:170-183](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L170-L183)
4. Upon completing the remote sign-in flow, the extension receives `oauthContext?.code` and `oauthContext?.verifier`, triggering the `connectWorkspace()` function. Sources: [packages/stripe-app/src/views/AppSettings.tsx:36-37](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L36-L37), [packages/stripe-app/src/views/AppSettings.tsx:127-131](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L127-L131)
5. `connectWorkspace()` calls `getToken({ code, verifier, mode })` to exchange the authorization code for an access token. Sources: [packages/stripe-app/src/views/AppSettings.tsx:82-86](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L82-L86)
6. The resulting token payload is serialized and stored via `setSecret({ stripe, name: "dub_token", payload })`. Sources: [packages/stripe-app/src/views/AppSettings.tsx:92-96](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L92-L96)
7. `getUserInfo({ token })` fetches associated workspace details, which are then stored via `setSecret({ stripe, name: "dub_workspace", payload })` after calling `updateWorkspace()`. Sources: [packages/stripe-app/src/views/AppSettings.tsx:98-114](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L98-L114)

> [!WARNING]
> If `code` or `verifier` are missing when the effect hook fires, `connectWorkspace()` exits immediately without executing token exchange, halting the handshake. Sources: [packages/stripe-app/src/views/AppSettings.tsx:78-80](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L78-80)

### Host Endpoints and Client Configuration

The authentication flow relies on predefined constants pointing to the Dub platform infrastructure. Sources: [packages/stripe-app/src/utils/constants.ts:1-6](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/utils/constants.ts#L1-L6)

| Constant Identifier | Value | Description | Sources |
| :--- | :--- | :--- | :--- |
| `DUB_CLIENT_ID` | `dub_app_517290377fe6b4dfcc8726a7061ba9b6da1c4d7d7d75f77a` | Unique application identifier for Dub OAuth requests | [packages/stripe-app/src/utils/constants.ts:2-3](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/utils/constants.ts#L2-L3) |
| `DUB_HOST` | `https://app.dub.co` | Base URL for Dub web application and authentication views | [packages/stripe-app/src/utils/constants.ts:4`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/utils/constants.ts#L4) |
| `DUB_API_HOST` | `https://api.dub.co` | Base URL for Dub REST API interactions | [packages/stripe-app/src/utils/constants.ts:5`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/utils/constants.ts#L5) |

> [!TIP]
> The `credentialsUsed` ref prevents duplicate execution of `connectWorkspace()` if component re-renders coincide with an active OAuth callback lifecycle. Sources: [packages/stripe-app/src/views/AppSettings.tsx:29`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L29), [packages/stripe-app/src/views/AppSettings.tsx:117`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L117), [packages/stripe-app/src/views/AppSettings.tsx:128`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L128)

## Workspace State and Context Hooks

### Workspace State and Context Hooks

### Overview

The `useWorkspace` hook manages workspace retrieval and synchronization within the Stripe UI extension context. It accepts a `Stripe` instance, maintains local loading and workspace states via React hooks, and exposes a mutation handle to reload workspace data on demand. Sources: [packages/stripe-app/src/hooks/use-workspace.ts:7-27](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/hooks/use-workspace.ts#L7-L27)

```typescript
export const useWorkspace = (stripe: Stripe) => {
  const [workspace, setWorkspace] = useState<Workspace | null>(null);
  const [isLoading, setIsLoading] = useState(true);

  const loadWorkspace = useCallback(async () => {
    setIsLoading(true);
    const fetchedWorkspace = await fetchWorkspace({ stripe });
    setWorkspace(fetchedWorkspace);
    setIsLoading(false);
  }, [stripe]);

  useEffect(() => {
    loadWorkspace();
  }, [loadWorkspace]);

  return {
    workspace,
    isLoading,
    mutate: loadWorkspace,
  };
};
```
Sources: [packages/stripe-app/src/hooks/use-workspace.ts:7-27](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/hooks/use-workspace.ts#L7-L27)

### Secret Storage and Workspace Retrieval

Workspace persistence relies on Stripe's secret storage layer. The internal `fetchWorkspace` helper queries secret storage for the `dub_workspace` entry using the provided `stripe` client instance, returning the deserialized `Workspace` object or `null` if unconfigured. Sources: [packages/stripe-app/src/hooks/use-workspace.ts:29-37](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/hooks/use-workspace.ts#L29-L37)

```typescript
async function fetchWorkspace({ stripe }: { stripe: Stripe }) {
  const workspace = await getSecret<Workspace>({
    stripe,
    name: "dub_workspace",
  });

  return workspace;
}
```
Sources: [packages/stripe-app/src/hooks/use-workspace.ts:29-37](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/hooks/use-workspace.ts#L29-L37)

> [!NOTE]
> The `useWorkspace` hook automatically triggers `loadWorkspace()` on initial component mount through a `useEffect` hook wrapped around `useCallback`. Sources: [packages/stripe-app/src/hooks/use-workspace.ts:11-20](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/hooks/use-workspace.ts#L11-L20)

### Stripe SDK Context Access

Views such as `AppSettings` receive extension context via the `ExtensionContextValue` interface provided by `@stripe/ui-extension-sdk/context`. This context supplies runtime properties including `userContext`, `oauthContext`, and `environment` configuration, alongside the initialized `stripe` SDK utility. Sources: [packages/stripe-app/src/views/AppSettings.tsx:1-28](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L1-L28)

| Context Property | Type / Source | Purpose | Sources |
| :--- | :--- | :--- | :--- |
| `userContext` | `ExtensionContextValue['userContext']` | Provides active Stripe account metadata, including sandbox status (`isSandbox`) and account ID (`id`) | [packages/stripe-app/src/views/AppSettings.tsx:25`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L25), [packages/stripe-app/src/views/AppSettings.tsx:61-63](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L61-L63), [packages/stripe-app/src/views/AppSettings.tsx:106-107](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L106-L107) |
| `oauthContext` | `ExtensionContextValue['oauthContext']` | Carries authorization callback parameters (`code` and `verifier`) returning from the OAuth flow | [packages/stripe-app/src/views/AppSettings.tsx:26`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L26), [packages/stripe-app/src/views/AppSettings.tsx:36-37](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L36-L37) |
| `environment` | `ExtensionContextValue['environment']` | Exposes current execution mode (`mode`) for API and authentication routing | [packages/stripe-app/src/views/AppSettings.tsx:27`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L27), [packages/stripe-app/src/views/AppSettings.tsx:63`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L63), [packages/stripe-app/src/views/AppSettings.tsx:85`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L85) |

## App Settings and Connection Controls

### Overview

The `AppSettings` component manages the extension settings user interface, governing workspace connectivity, OAuth callback handling, and credentials lifecycle. Built with Stripe UI extension components such as `SignInView`, `Banner`, `Box`, and `Spinner`, the view dynamically renders either an active workspace banner with a destructive disconnect control or a sign-in view prompting users to link their Dub account. Sources: [packages/stripe-app/src/views/AppSettings.tsx:4-10](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L4-L10), [packages/stripe-app/src/views/AppSettings.tsx:24-35](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L24-L35), [packages/stripe-app/src/views/AppSettings.tsx:147-195](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L147-L195)

> [!NOTE]
> When `isLoading` or `connecting` is true, `AppSettings` immediately renders a centered `Spinner` component with a `large` size, blocking UI interaction during asynchronous token exchanges and workspace lookups. Sources: [packages/stripe-app/src/views/AppSettings.tsx:143-145](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L143-L145)

### Connection Call-Chain Execution

When an authorization code returns from the OAuth redirect, the component automatically executes `connectWorkspace()` inside a `useEffect` hook. The exact call chain proceeds as follows:

1. `getToken()` — Exchanges the authorization code and verifier for an API token under the active environment mode. Sources: [packages/stripe-app/src/views/AppSettings.tsx:82-86](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L82-L86)
2. `setSecret()` — Persists the serialized token payload into Stripe secret storage under the name `dub_token`. Sources: [packages/stripe-app/src/views/AppSettings.tsx:92-96](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L92-L96)
3. `getUserInfo()` — Queries Dub workspace metadata using the acquired token. Sources: [packages/stripe-app/src/views/AppSettings.tsx:98`﻿](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L98)
4. `updateWorkspace()` — Links the Dub account to the Stripe account ID, resolving stripe mode between sandbox and live execution based on `userContext.account.isSandbox`. Sources: [packages/stripe-app/src/views/AppSettings.tsx:104-108](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L104-L108)
5. `setSecret()` — Stores the retrieved workspace metadata in secret storage under `dub_workspace`. Sources: [packages/stripe-app/src/views/AppSettings.tsx:110-114](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L110-L114)
6. `mutate()` — Refreshes the local workspace hook state, concluding with `credentialsUsed.current = true`. Sources: [packages/stripe-app/src/views/AppSettings.tsx:116-117](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L116-L117)

```typescript
  const connectWorkspace = async () => {
    setConnecting(true);

    if (!code || !verifier) {
      return;
    }

    const token = await getToken({
      code,
      verifier,
      mode: environment.mode,
    });

    if (!token) {
      return;
    }

    await setSecret({
      stripe,
      name: "dub_token",
      payload: JSON.stringify(token),
    });

    const workspace = await getUserInfo({ token });

    if (!workspace) {
      return;
    }

    await updateWorkspace({
      token,
      accountId: userContext.account.id,
      stripeMode: userContext.account.isSandbox ? "sandbox" : environment.mode,
    });

    await setSecret({
      stripe,
      name: "dub_workspace",
      payload: JSON.stringify(workspace),
    });

    await mutate();
    credentialsUsed.current = true;
    setConnecting(false);
  };
```
Sources: [packages/stripe-app/src/views/AppSettings.tsx:75-119](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L75-L119)

### Disconnection and Cleanup

Disconnecting a workspace reverses the linkage via the `disconnectWorkspace` routine. It invokes `getValidToken()` to authenticate the removal request, deletes both secret keys (`dub_workspace` and `dub_token`) in parallel using `Promise.all()`, updates the remote workspace with a `null` account ID, and triggers a state mutation. Sources: [packages/stripe-app/src/views/AppSettings.tsx:40-69](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L40-L69)

| Action Function | Target Keys / Parameters | Execution Behavior | Sources |
| :--- | :--- | :--- | :--- |
| `disconnectWorkspace` | `dub_workspace`, `dub_token` | Deletes stored secrets, disassociates the workspace account ID via API, and resets local workspace state | [packages/stripe-app/src/views/AppSettings.tsx:40-69](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L40-L69) |
| `connectWorkspace` | `dub_token`, `dub_workspace` | Exchanges OAuth code for token, stores credentials, registers account mapping, and updates workspace state | [packages/stripe-app/src/views/AppSettings.tsx:75-119](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L75-L119) |

> [!WARNING]
> The `useEffect` dependency array monitors `[workspace, oauthState, code, verifier]`. If `code` and `verifier` are present without an existing workspace and `credentialsUsed.current` is false, it executes `connectWorkspace()` exactly once, preventing duplicate authorization code exchanges. Sources: [packages/stripe-app/src/views/AppSettings.tsx:121-141](https://github.com/blade47/dub/blob/HEAD/packages/stripe-app/src/views/AppSettings.tsx#L121-L141)

## Dashboard Integration Settings and Installation

### Overview

The Dub web dashboard provides integration management interfaces and UI triggers for installing the Stripe marketplace app. Within a workspace's settings, the dashboard maps registered integrations to their respective settings components, utilizing `STRIPE_INTEGRATION_ID` to render Stripe-specific UI elements. Sources: [apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/[integrationSlug]/page-client.tsx:67-75](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/settings/integrations/%5BintegrationSlug%5D/page-client.tsx#L67-L75)

### Connection State Banners

For installed Stripe integrations, the client evaluates settings against `stripeIntegrationSettingsSchema` to determine the execution mode. Based on the parsed mode, it configures visual status banners distinguishing between live, test, and sandbox environments. Sources: [apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/[integrationSlug]/page-client.tsx:123-158](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/settings/integrations/%5BintegrationSlug%5D/page-client.tsx#L123-L158)

| Stripe Mode | Background Style | Caption Style | Icon Indicator | Sources |
| :--- | :--- | :--- | :--- | :--- |
| `live` | `bg-emerald-50` | `text-emerald-900` | `CheckCircleFill` (emerald) | [apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/[integrationSlug]/page-client.tsx:135-140](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/settings/integrations/%5BintegrationSlug%5D/page-client.tsx#L135-L140) |
| `test` | `bg-[#F0F7FF]` | `text-blue-900/80` | `Flask` (blue) | [apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/[integrationSlug]/page-client.tsx:141-147](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/settings/integrations/[integrationSlug]/page-client.tsx#L141-L147) |
| `sandbox` | `bg-orange-50` | `text-orange-900/80` | `Flask` (orange) | [apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/[integrationSlug]/page-client.tsx:148-155](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/%5Bslug%5D/(ee)/settings/integrations/[integrationSlug]/page-client.tsx#L148-L155) |

> [!NOTE]
> The uninstallation link dynamically adjusts its URL based on the active Stripe mode, directing users to the appropriate test or live app installation management path in the Stripe Dashboard. Sources: [apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/[integrationSlug]/page-client.tsx:160-164](https://github.com/blade47/dub/blob/HEAD/apps/web/app/app.dub.co/(dashboard)/[slug]/(ee)/settings/integrations/[integrationSlug]/page-client.tsx#L160-L164)

### Installation Flow Triggers

The installation trigger uses `InstallStripeIntegrationButton` to poll active workspace integrations and manage installation state transitions. If the Stripe integration is not yet active, it renders a call-to-action button linking to the workspace integration settings page while polling state every 1000ms to 5000ms. Sources: [apps/web/ui/guides/install-stripe-integration-button.tsx:13-31](https://github.com/blade47/dub/blob/HEAD/apps/web/ui/guides/install-stripe-integration-button.tsx#L13-31), [apps/web/ui/guides/install-stripe-integration-button.tsx:52-71](https://github.com/blade47/dub/blob/HEAD/apps/web/ui/guides/install-stripe-integration-button.tsx#L52-71)

## Related

- [Stripe Billing and Webhooks](https://www.doc0.dev/docs/934e554a-e6a1-476f-bb2f-23e62d86c3fd/technical/external-integrations/stripe-billing-and-webhooks)
- [OAuth2 Provider and API Tokens](https://www.doc0.dev/docs/934e554a-e6a1-476f-bb2f-23e62d86c3fd/technical/authentication-and-security/oauth2-provider-and-api-tokens)


## Sitemap

See the full [sitemap](https://www.doc0.dev/docs/934e554a-e6a1-476f-bb2f-23e62d86c3fd/llms.txt) for all pages in this wiki.
