diff --git a/v2/demo-apps/.env.example b/v2/demo-apps/.env.example
index 0bc6c0dd..7edeb934 100644
--- a/v2/demo-apps/.env.example
+++ b/v2/demo-apps/.env.example
@@ -47,5 +47,8 @@ COMPILOT_API_KEY_LANDING_KYB
COMPILOT_WORKFLOW_ID_LANDING_KYB
NEXT_PUBLIC_LANDING_KYB_COMPANY
+COMPILOT_API_KEY_NO_WALLET_KYB
+COMPILOT_WORKFLOW_ID_NO_WALLET_KYB
+
NEXT_PUBLIC_AMOY_HTTP_PROVIDER_URL=
NEXT_PUBLIC_SEPOLIA_HTTP_PROVIDER_URL=
diff --git a/v2/demo-apps/src/env.mjs b/v2/demo-apps/src/env.mjs
index 73d9f0dc..8124a48c 100644
--- a/v2/demo-apps/src/env.mjs
+++ b/v2/demo-apps/src/env.mjs
@@ -144,6 +144,30 @@ export const env = createEnv({
.describe(
"The workflow ID for the ComPilot API -> https://dashboard.compilot.ai/: ComPilot Multichain Demo dApp",
),
+
+ COMPILOT_API_KEY_LANDING_KYB: z
+ .string()
+ .describe(
+ "The API key for the ComPilot API -> https://dashboard.compilot.ai/: ComPilot Landing KYB Demo App",
+ ),
+
+ COMPILOT_WORKFLOW_ID_LANDING_KYB: z
+ .string()
+ .describe(
+ "The workflow ID for the ComPilot API -> https://dashboard.compilot.ai/: ComPilot Landing KYB Demo App",
+ ),
+
+ COMPILOT_API_KEY_NO_WALLET_KYB: z
+ .string()
+ .describe(
+ "The API key for the ComPilot API -> https://dashboard.compilot.ai/: ComPilot no wallet KYB Demo App",
+ ),
+
+ COMPILOT_WORKFLOW_ID_NO_WALLET_KYB: z
+ .string()
+ .describe(
+ "The workflow ID for the ComPilot API -> https://dashboard.compilot.ai/: ComPilot no wallet KYB Demo App",
+ ),
},
/**
@@ -216,6 +240,14 @@ export const env = createEnv({
process.env.COMPILOT_API_KEY_MULTICHAIN_DEMO,
COMPILOT_WORKFLOW_ID_MULTICHAIN_DEMO:
process.env.COMPILOT_WORKFLOW_ID_MULTICHAIN_DEMO,
+
+ COMPILOT_API_KEY_LANDING_KYB: process.env.COMPILOT_API_KEY_LANDING_KYB,
+ COMPILOT_WORKFLOW_ID_LANDING_KYB:
+ process.env.COMPILOT_WORKFLOW_ID_LANDING_KYB,
+
+ COMPILOT_API_KEY_NO_WALLET_KYB: process.env.COMPILOT_API_KEY_NO_WALLET_KYB,
+ COMPILOT_WORKFLOW_ID_NO_WALLET_KYB:
+ process.env.COMPILOT_WORKFLOW_ID_NO_WALLET_KYB,
},
/**
* Run `build` or `dev` with `SKIP_ENV_VALIDATION` to skip env validation.
diff --git a/v2/demo-apps/src/features/landing-kyb-without-wallet/Layout/Layout.tsx b/v2/demo-apps/src/features/landing-kyb-without-wallet/Layout/Layout.tsx
new file mode 100644
index 00000000..12b22617
--- /dev/null
+++ b/v2/demo-apps/src/features/landing-kyb-without-wallet/Layout/Layout.tsx
@@ -0,0 +1,18 @@
+import type { ReactNode } from 'react';
+
+interface LayoutProps {
+ children: ReactNode;
+ header?: ReactNode;
+}
+
+export const Layout = ({ children, header }: LayoutProps) => {
+ return (
+
+ {header &&
+ }
+
+ {children}
+
+
+ );
+};
diff --git a/v2/demo-apps/src/features/landing-kyb-without-wallet/identity/compilotConfig.ts b/v2/demo-apps/src/features/landing-kyb-without-wallet/identity/compilotConfig.ts
new file mode 100644
index 00000000..5a38c868
--- /dev/null
+++ b/v2/demo-apps/src/features/landing-kyb-without-wallet/identity/compilotConfig.ts
@@ -0,0 +1,26 @@
+import { createAuthAdapter, createConfig } from "@compilot/react-sdk";
+import "@/features/root/configureReactDemoEnv";
+import { useAuthStore } from "./useKybWithoutWalletAuthentication";
+
+export const compilotConfig = createConfig({
+ authAdapter: createAuthAdapter({
+ // This is a fake implementation of the auth adapter
+ createSession: async () => {
+ const authState = useAuthStore.getState();
+ if (!authState.isAuthenticated || !authState.userId) {
+ throw new Error("User is not authenticated");
+ }
+ const session = await fetch("/api/landing-kyb-not-wallet/access-token", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ userId: authState.userId,
+ }),
+ });
+
+ return session.json();
+ },
+ }),
+});
diff --git a/v2/demo-apps/src/features/landing-kyb-without-wallet/identity/fetchAccessToken.ts b/v2/demo-apps/src/features/landing-kyb-without-wallet/identity/fetchAccessToken.ts
new file mode 100644
index 00000000..9f64a977
--- /dev/null
+++ b/v2/demo-apps/src/features/landing-kyb-without-wallet/identity/fetchAccessToken.ts
@@ -0,0 +1,31 @@
+interface AccessTokenRequest {
+ userId: string;
+}
+
+interface AccessTokenResponse {
+ accessToken: string;
+}
+
+export async function fetchAccessToken(
+ requestData: AccessTokenRequest,
+): Promise {
+ try {
+ const response = await fetch(`/api/landing-kyb-not-wallet/access-token`, {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(requestData),
+ });
+
+ if (!response.ok) {
+ throw new Error("Failed to fetch access token");
+ }
+
+ const data = (await response.json()) as AccessTokenResponse;
+ return data;
+ } catch (error) {
+ console.error("Error fetching access token:", error);
+ throw new Error("Error fetching access token");
+ }
+}
diff --git a/v2/demo-apps/src/features/landing-kyb-without-wallet/identity/useKybWithoutWalletAuthentication.tsx b/v2/demo-apps/src/features/landing-kyb-without-wallet/identity/useKybWithoutWalletAuthentication.tsx
new file mode 100644
index 00000000..6fc8702b
--- /dev/null
+++ b/v2/demo-apps/src/features/landing-kyb-without-wallet/identity/useKybWithoutWalletAuthentication.tsx
@@ -0,0 +1,89 @@
+import { useMutation } from "@tanstack/react-query";
+import { create } from "zustand";
+import { createJSONStorage, devtools, persist } from "zustand/middleware";
+import { immer } from "zustand/middleware/immer";
+import { fetchAccessToken } from "./fetchAccessToken";
+
+export const useMockKybWithoutWallet = () => {
+ const authStore = useAuthStore((state) => state);
+
+ const logout = useMutation({
+ mutationFn: async () => {
+ await Promise.resolve(authStore.logout());
+ },
+ });
+
+ const authenticate = useMutation({
+ mutationFn: async (variables: { userId: string }) => {
+ const response = await fetchAccessToken({
+ userId: variables.userId,
+ });
+ const { accessToken } = response;
+ return {
+ accessToken,
+ testUser: variables.userId,
+ };
+ },
+ onSuccess: (data) => {
+ authStore.authenticate(data.accessToken, data.testUser);
+ },
+ onError: (error) => {
+ console.error(error);
+ },
+ });
+
+ return {
+ authenticate,
+ logout,
+ accessToken: authStore.accessToken,
+ isAuthenticated: authStore.isAuthenticated,
+ isIdentityClientInit: authStore.isIdentityClientInit,
+ setIsIdentityClientInit: authStore.setIsIdentityClientInit,
+ userId: authStore.userId,
+ };
+};
+
+interface IAuthStore {
+ accessToken?: string;
+ isAuthenticated: boolean;
+ userId?: string;
+ isIdentityClientInit: boolean;
+ setIsIdentityClientInit: (isInit: boolean) => void;
+ authenticate: (accessToken: string, userId: string) => void;
+ logout: () => void;
+}
+
+export const useAuthStore = create()(
+ devtools(
+ persist(
+ immer((set) => ({
+ accessToken: undefined,
+ isAuthenticated: false,
+ isIdentityClientInit: false,
+ setIsIdentityClientInit: (isInit: boolean) => {
+ set((state) => {
+ state.isIdentityClientInit = isInit;
+ });
+ },
+ authenticate: (accessToken: string, userId: string) => {
+ set((state) => {
+ state.accessToken = accessToken;
+ state.isAuthenticated = true;
+ state.userId = userId;
+ });
+ },
+ logout: () => {
+ set((state) => {
+ state.accessToken = undefined;
+ state.isAuthenticated = false;
+ state.userId = undefined;
+ });
+ },
+ })),
+ {
+ name: "kyb-without-wallet",
+ storage: createJSONStorage(() => sessionStorage),
+ },
+ ),
+ ),
+);
diff --git a/v2/demo-apps/src/pages/api/landing-kyb-not-wallet/access-token.ts b/v2/demo-apps/src/pages/api/landing-kyb-not-wallet/access-token.ts
new file mode 100644
index 00000000..1a802502
--- /dev/null
+++ b/v2/demo-apps/src/pages/api/landing-kyb-not-wallet/access-token.ts
@@ -0,0 +1,37 @@
+import type { NextApiRequest, NextApiResponse } from "next";
+import { env } from "@/env.mjs";
+import { createSdk } from "@compilot/js-sdk";
+
+import "@/features/root/configureNodeDemoEnv";
+
+const apiClient = createSdk({
+ webhookSecret: env.COMPILOT_WEBHOOK_SECRET_BANK_KYB,
+ apiKey: env.COMPILOT_API_KEY_NO_WALLET_KYB,
+});
+
+export default async function handler(
+ req: NextApiRequest,
+ res: NextApiResponse,
+) {
+ if (req.method !== "POST") {
+ res.setHeader("Allow", ["POST"]);
+ res.status(405).end(`Method ${req.method} Not Allowed`);
+ return;
+ }
+
+ try {
+ // Get the current user ID
+ // NOTE: This is a simplified example. In a real-world application, you should use a more secure method to get the user ID.
+ const userId = req.body.userId;
+
+ const authSession = await apiClient.createSession({
+ externalCustomerId: userId,
+ workflowId: env.COMPILOT_WORKFLOW_ID_NO_WALLET_KYB,
+ });
+
+ res.status(200).json(authSession);
+ } catch (error) {
+ console.error("API call error:", error);
+ res.status(500).json({ error: "Failed to fetch access token" });
+ }
+}
diff --git a/v2/demo-apps/src/pages/index.tsx b/v2/demo-apps/src/pages/index.tsx
index e8395199..bdc45eea 100644
--- a/v2/demo-apps/src/pages/index.tsx
+++ b/v2/demo-apps/src/pages/index.tsx
@@ -106,6 +106,15 @@ const PROJECTS: AppCardProps[] = [
tags: [VCV_TAG, OFF_TAG, AS_TAG],
poweredBy: "/images/poweredBy/green-bank.svg",
},
+ {
+ url: "/landing-kyb-not-wallet",
+ name: "KYB without wallet",
+ description:
+ "Short description for this app example that we showcase here. Better to have a few lines of text, so not very short if possible",
+ image: "/images/apps/banking.svg",
+ tags: [VCV_TAG, OFF_TAG, AS_TAG],
+ poweredBy: "/images/poweredBy/green-bank.svg",
+ },
{
url: "/bank-web3",
name: "Web3 Banking",
diff --git a/v2/demo-apps/src/pages/landing-kyb-not-wallet.tsx b/v2/demo-apps/src/pages/landing-kyb-not-wallet.tsx
new file mode 100644
index 00000000..fc67e320
--- /dev/null
+++ b/v2/demo-apps/src/pages/landing-kyb-not-wallet.tsx
@@ -0,0 +1,102 @@
+import { WagmiProvider } from "wagmi";
+import { Layout } from "@/features/landing-kyb/Layout/Layout";
+import { wagmiConfig } from "@/features/root/web3/wagmiConfig";
+import {
+ ComPilotProvider,
+ useOpenWidget,
+ useDisconnect,
+} from "@compilot/react-sdk";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+import { compilotConfig } from "@/features/landing-kyb-without-wallet/identity/compilotConfig";
+import { useMockKybWithoutWallet } from "@/features/landing-kyb-without-wallet/identity/useKybWithoutWalletAuthentication";
+
+const queryClient = new QueryClient();
+
+const Home = () => {
+ return (
+
+
+
+
+
+
+
+ );
+};
+
+const HomeContent = () => {
+ const openWidget = useOpenWidget();
+ const { disconnect } = useDisconnect();
+ const companyName = process.env.NEXT_PUBLIC_LANDING_KYB_COMPANY ?? "";
+ const { authenticate, isAuthenticated, logout } = useMockKybWithoutWallet();
+
+ const handleClick = async () => {
+ try {
+ await disconnect();
+ await new Promise((resolve) => setTimeout(resolve, 100));
+ await openWidget.openWidget();
+ } catch (error) {
+ await disconnect();
+ }
+ };
+
+ return (
+
+
+
+
+ {/* Left Column - Title and Button */}
+
+
+ {companyName} Verification
+
+
+ {isAuthenticated ? (
+
+
+
+
+
+ ) : (
+
+ )}
+
+
+
+
+
+ );
+};
+
+export default Home;