diff --git a/apps/playground-web/public/ub.png b/apps/playground-web/public/ub.png
new file mode 100644
index 00000000000..6448e1d2a10
Binary files /dev/null and b/apps/playground-web/public/ub.png differ
diff --git a/apps/playground-web/src/app/connect/pay/backend/layout.tsx b/apps/playground-web/src/app/connect/pay/backend/layout.tsx
new file mode 100644
index 00000000000..0b0c4052825
--- /dev/null
+++ b/apps/playground-web/src/app/connect/pay/backend/layout.tsx
@@ -0,0 +1,21 @@
+import type React from "react";
+import { APIHeader } from "../../../../components/blocks/APIHeader";
+
+export default function Layout(props: {
+ children: React.ReactNode;
+}) {
+ return (
+
+
HTTP API to bridge, swap and onramp to and from any currency>
+ }
+ docsLink="https://portal.thirdweb.com/connect/pay/overview"
+ heroLink="/ub.png"
+ />
+
+ {props.children}
+
+ );
+}
diff --git a/apps/playground-web/src/app/connect/pay/backend/page.tsx b/apps/playground-web/src/app/connect/pay/backend/page.tsx
new file mode 100644
index 00000000000..26681e88431
--- /dev/null
+++ b/apps/playground-web/src/app/connect/pay/backend/page.tsx
@@ -0,0 +1,79 @@
+import { Table, TableBody, TableCell, TableRow } from "@/components/ui/table";
+import Link from "next/link";
+import { getBridgePaths } from "./utils";
+
+export default async function Page() {
+ try {
+ const paths = await getBridgePaths();
+ return (
+
+
+ Universal Bridge REST API
+
+
+ Directly interact with the Universal Bridge API from your backend,
+ using standard REST api.
+
+
+
+ {
+ if (!pathObj) {
+ throw new Error(`Path not found: ${pathName}`);
+ }
+ return {
+ name: pathName,
+ description: pathObj.get?.description || "",
+ link: `/connect/pay/backend/reference?route=${pathName}`,
+ };
+ })}
+ />
+
+
+ );
+ } catch (error) {
+ console.error(error);
+ return Error fetching API spec
;
+ }
+}
+
+function BlueprintSection(props: {
+ title: string;
+ blueprints: { name: string; description: string; link: string }[];
+}) {
+ return (
+
+
+
{props.title}
+
+
+
+ {props.blueprints.map((item) => (
+
+
+
+
+
+
{item.name}
+
+ {item.description}
+
+
+
+
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/apps/playground-web/src/app/connect/pay/backend/reference/page.tsx b/apps/playground-web/src/app/connect/pay/backend/reference/page.tsx
new file mode 100644
index 00000000000..1f2fda67f19
--- /dev/null
+++ b/apps/playground-web/src/app/connect/pay/backend/reference/page.tsx
@@ -0,0 +1,70 @@
+import {
+ Breadcrumb,
+ BreadcrumbItem,
+ BreadcrumbLink,
+ BreadcrumbList,
+ BreadcrumbSeparator,
+} from "@/components/ui/breadcrumb";
+import { redirect } from "next/navigation";
+import { THIRDWEB_CLIENT } from "../../../../../lib/client";
+import { isProd } from "../../../../../lib/env";
+import { BlueprintPlayground } from "../../../../insight/[blueprint_slug]/blueprint-playground.client";
+import { getBridgePaths } from "../utils";
+
+export default async function Page(props: {
+ searchParams: Promise<{
+ route: string;
+ }>;
+}) {
+ const params = await props.searchParams;
+
+ // invalid url
+ if (!params.route) {
+ redirect("/connect/pay/backend");
+ }
+
+ const thirdwebDomain = !isProd ? "thirdweb-dev" : "thirdweb";
+ const domain = `https://bridge.${thirdwebDomain}.com`;
+
+ const paths = await getBridgePaths();
+ const pathMetadata = paths.find(([path]) => path === params.route)?.[1]?.get;
+
+ // invalid url
+ if (!pathMetadata) {
+ redirect("/connect/pay/backend");
+ }
+
+ const title = pathMetadata.summary || "";
+ return (
+
+
+
+ {title}
+
+
+
+ );
+}
+
+function Breadcrumbs() {
+ return (
+
+
+
+
+ Universal Bridge API
+
+
+
+
+
+ );
+}
diff --git a/apps/playground-web/src/app/connect/pay/backend/utils.ts b/apps/playground-web/src/app/connect/pay/backend/utils.ts
new file mode 100644
index 00000000000..eb75e377ffc
--- /dev/null
+++ b/apps/playground-web/src/app/connect/pay/backend/utils.ts
@@ -0,0 +1,13 @@
+import type { OpenAPIV3 } from "openapi-types";
+import { isProd } from "../../../../lib/env";
+
+export async function getBridgePaths() {
+ const thirdwebDomain = !isProd ? "thirdweb-dev" : "thirdweb";
+ const res = await fetch(`https://bridge.${thirdwebDomain}.com/openapi.json`);
+ const openapiJson = (await res.json()) as OpenAPIV3.Document;
+ return Object.entries(openapiJson.paths).filter(
+ ([, pathObj]) =>
+ pathObj?.get?.deprecated === undefined ||
+ pathObj?.get?.deprecated === false,
+ );
+}
diff --git a/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx b/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx
index 333e9462746..211271f62fa 100644
--- a/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx
+++ b/apps/playground-web/src/app/insight/[blueprint_slug]/blueprint-playground.client.tsx
@@ -35,7 +35,6 @@ import {
useForm,
} from "react-hook-form";
import { z } from "zod";
-import { isProd } from "../../../lib/env";
import type { BlueprintParameter, BlueprintPathMetadata } from "../utils";
export function BlueprintPlayground(props: {
@@ -44,6 +43,7 @@ export function BlueprintPlayground(props: {
clientId: string;
path: string;
supportedChainIds: number[];
+ domain: string;
}) {
const [abortController, setAbortController] =
useState(null);
@@ -56,6 +56,9 @@ export function BlueprintPlayground(props: {
try {
const res = await fetch(url, {
signal: controller.signal,
+ headers: {
+ "x-client-id": props.clientId,
+ },
});
return {
status: res.status,
@@ -78,8 +81,6 @@ export function BlueprintPlayground(props: {
},
});
- const thirdwebDomain = !isProd ? "thirdweb-dev" : "thirdweb";
-
return (
diff --git a/apps/playground-web/src/app/insight/[blueprint_slug]/page.tsx b/apps/playground-web/src/app/insight/[blueprint_slug]/page.tsx
index e5fd2979d3a..9604218d930 100644
--- a/apps/playground-web/src/app/insight/[blueprint_slug]/page.tsx
+++ b/apps/playground-web/src/app/insight/[blueprint_slug]/page.tsx
@@ -7,6 +7,7 @@ import {
} from "@/components/ui/breadcrumb";
import { redirect } from "next/navigation";
import { THIRDWEB_CLIENT } from "../../../lib/client";
+import { isProd } from "../../../lib/env";
import { fetchBlueprintSpec } from "../utils";
import { BlueprintPlayground } from "./blueprint-playground.client";
@@ -26,6 +27,9 @@ export default async function Page(props: {
redirect("/insight");
}
+ const thirdwebDomain = !isProd ? "thirdweb-dev" : "thirdweb";
+ const domain = `https://insight.${thirdwebDomain}.com`;
+
const [blueprintSpec] = await Promise.all([
fetchBlueprintSpec({
blueprintId: params.blueprint_slug,
@@ -58,6 +62,7 @@ export default async function Page(props: {
clientId={THIRDWEB_CLIENT.clientId}
path={searchParams.path}
supportedChainIds={supportedChainIds}
+ domain={domain}
/>
);
diff --git a/apps/playground-web/src/app/navLinks.ts b/apps/playground-web/src/app/navLinks.ts
index a1ce0f3f712..037cc6beced 100644
--- a/apps/playground-web/src/app/navLinks.ts
+++ b/apps/playground-web/src/app/navLinks.ts
@@ -60,28 +60,6 @@ export const staticSidebarLinks: SidebarLink[] = [
},
],
},
- {
- name: "Universal Bridge",
- expanded: false,
- links: [
- {
- name: "UI Component",
- href: "/connect/pay",
- },
- {
- name: "Fund Wallet",
- href: "/connect/pay/fund-wallet",
- },
- {
- name: "Commerce",
- href: "/connect/pay/commerce",
- },
- {
- name: "Transactions",
- href: "/connect/pay/transactions",
- },
- ],
- },
{
name: "Auth",
href: "/connect/auth",
@@ -124,6 +102,34 @@ export const staticSidebarLinks: SidebarLink[] = [
},
];
+const universalBridgeSidebarLinks: SidebarLink = {
+ name: "Universal Bridge",
+ isCollapsible: false,
+ expanded: false,
+ links: [
+ {
+ name: "UI Component",
+ href: "/connect/pay",
+ },
+ {
+ name: "Fund Wallet",
+ href: "/connect/pay/fund-wallet",
+ },
+ {
+ name: "Commerce",
+ href: "/connect/pay/commerce",
+ },
+ {
+ name: "Transactions",
+ href: "/connect/pay/transactions",
+ },
+ {
+ name: "Backend API",
+ href: "/connect/pay/backend",
+ },
+ ],
+};
+
const engineSidebarLinks: SidebarLink = {
name: "Engine",
isCollapsible: false,
@@ -167,13 +173,14 @@ export async function getSidebarLinks() {
const sidebarLinks: SidebarLink[] = [
...staticSidebarLinks,
+ universalBridgeSidebarLinks,
+ engineSidebarLinks,
{
name: "Insight",
isCollapsible: false,
expanded: false,
links: insightLinks,
},
- engineSidebarLinks,
];
return sidebarLinks;
diff --git a/apps/playground-web/src/lib/client.ts b/apps/playground-web/src/lib/client.ts
index e6be51abf73..ed34bcc545f 100644
--- a/apps/playground-web/src/lib/client.ts
+++ b/apps/playground-web/src/lib/client.ts
@@ -19,6 +19,7 @@ export const THIRDWEB_CLIENT = createThirdwebClient(
process.env.THIRDWEB_SECRET_KEY
? {
secretKey: process.env.THIRDWEB_SECRET_KEY,
+ clientId: process.env.NEXT_PUBLIC_THIRDWEB_CLIENT_ID as string,
config: {
storage: isDev
? {
diff --git a/apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts b/apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts
index 780bc6428b9..1798f467815 100644
--- a/apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts
+++ b/apps/portal/src/app/references/components/TDoc/utils/getSidebarLinkgroups.ts
@@ -35,6 +35,7 @@ const tagsToGroup = {
"@extension": "Extensions",
"@rpc": "RPC",
"@transaction": "Transactions",
+ "@bridge": "Universal Bridge",
"@buyCrypto": "Buy Crypto",
"@utils": "Utils",
"@chain": "Chain",
@@ -60,6 +61,7 @@ const sidebarGroupOrder: TagKey[] = [
"@account",
"@contract",
"@transaction",
+ "@bridge",
"@nebula",
"@social",
"@auth",
diff --git a/packages/thirdweb/scripts/typedoc.mjs b/packages/thirdweb/scripts/typedoc.mjs
index 2d42ffd0108..dd7f8ceddff 100644
--- a/packages/thirdweb/scripts/typedoc.mjs
+++ b/packages/thirdweb/scripts/typedoc.mjs
@@ -10,6 +10,9 @@ const app = await Application.bootstrapWithPlugins({
"src/adapters/eip1193/index.ts",
"src/wallets/smart/presets/index.ts",
"src/ai/index.ts",
+ "src/bridge/index.ts",
+ "src/bridge/Buy.ts",
+ "src/bridge/Sell.ts",
],
exclude: [
"src/exports/*.native.ts",
diff --git a/packages/thirdweb/src/extensions/thirdweb/write/publish.ts b/packages/thirdweb/src/extensions/thirdweb/write/publish.ts
index 0c098feff2b..5ae855d6719 100644
--- a/packages/thirdweb/src/extensions/thirdweb/write/publish.ts
+++ b/packages/thirdweb/src/extensions/thirdweb/write/publish.ts
@@ -39,7 +39,7 @@ export type PublishContractParams = {
* metadata,
* });
* ```
- * @extension thirdweb
+ * @extension THIRDWEB
*/
export function publishContract(
options: BaseTransactionOptions,
diff --git a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx
index 7161d9e44c7..d7efb970c35 100644
--- a/packages/thirdweb/src/react/web/ui/PayEmbed.tsx
+++ b/packages/thirdweb/src/react/web/ui/PayEmbed.tsx
@@ -256,6 +256,7 @@ export type PayEmbedProps = {
* buyWithFiat: false,
* }}
* />
+ * ```
*
* ### Customize the UI
*