To use Mural with V0, create a Next.js API route at app/api/mural/route.ts that uses the Mural REST API to fetch workspace and mural data. Store your Mural OAuth access token or API key in Vercel Dashboard → Settings → Environment Variables. V0 generates the interface for displaying mural thumbnails, workspace lists, or collaboration activity; the API route handles all Mural API calls server-side to protect your credentials.
Building Mural-Connected Apps and Dashboards with V0
Mural is the structured facilitation platform of choice for design teams, agile coaches, and workshop facilitators. Unlike general-purpose whiteboards, Mural emphasizes guided facilitation — templates for retrospectives, design sprints, customer journey mapping, and brainstorming sessions. For V0 founders building team dashboards, project management tools, or client portals, the Mural API lets you surface whiteboard content, track workshop outcomes, and display active collaboration sessions directly in your app.
The most common V0-Mural integration pattern is a workspace gallery or mural index — a page that lists all murals in a workspace with their thumbnails, creation dates, and collaborator counts. This is valuable for team portals where members need a single place to find all their Mural boards without switching between apps. You can also build facilitation dashboards that track which murals were recently active, or client portals that surface only the specific murals relevant to each client project.
Mural's API follows a hierarchical structure: Workspaces contain Rooms, Rooms contain Murals, and Murals contain Widgets (sticky notes, shapes, text, images). Most use cases for V0 integrations need the workspace and mural level — listing available boards and linking out to them. Embedding interactive Mural content requires their official embed functionality, which works via iframe similarly to other whiteboard tools.
Integration method
V0 generates your collaboration dashboard or mural gallery interface while a Next.js API route fetches workspace and mural data from the Mural REST API. Authentication uses OAuth 2.0 — for internal tools, you obtain a long-lived access token from Mural's developer portal and store it in Vercel environment variables. The API route proxies all Mural API calls server-side so the access token never reaches the browser.
Prerequisites
- A V0 account with a Next.js project at v0.dev
- A Mural account with at least one workspace and mural created
- A Mural Developer Application registered at developers.mural.co to get OAuth credentials
- A Vercel account with your V0 project deployed via GitHub
- Workspace admin access (required to get API credentials in most Mural plans)
Step-by-step guide
Register a Mural Developer Application
Register a Mural Developer Application
Mural's API uses OAuth 2.0 for authentication. To get API access, you need to register a developer application in Mural's developer portal, which gives you a Client ID and Client Secret used to obtain access tokens. Go to developers.mural.co and sign in with your Mural account. Navigate to the Applications section and click Create Application. Give your app a name (e.g., 'V0 Dashboard Integration'), a brief description, and set the redirect URI to your Vercel deployment URL followed by /api/mural/callback — for example, https://your-project.vercel.app/api/mural/callback. This redirect URI is used during the OAuth authorization flow. After creating the application, Mural will show you the Client ID and Client Secret. Copy both immediately. For internal tools where you are the only user, you can streamline authentication by using Mural's client credentials flow or by manually obtaining a long-lived access token through the OAuth authorization code flow once and storing it as an environment variable. For the simplest setup for a single-tenant internal tool: complete the OAuth authorization flow once manually (using a tool like Postman or the Mural API Explorer), obtain an access token and refresh token, then store both in Vercel environment variables. Your API route uses the access token for requests and refreshes it using the refresh token when it expires. Mural access tokens typically expire after one hour. Note a key difference from simpler APIs: Mural does not offer static API keys for personal use the way tools like Calendly or OnceHub do. All access goes through OAuth, which adds complexity. For a V0 internal tool, the 'store a long-lived token' approach is the most practical path.
Pro tip: Mural's API has different access levels per workspace plan. Enterprise plans have broader API access. If you encounter 403 errors on certain endpoints, check whether your Mural subscription includes API access for those features.
Expected result: You have a Mural Developer Application with a Client ID and Client Secret. You have obtained an initial access token and refresh token through the OAuth flow.
Store Mural Credentials in Vercel
Store Mural Credentials in Vercel
Add your Mural authentication credentials to Vercel so your API route can authenticate with the Mural API in production. Open Vercel Dashboard → your project → Settings → Environment Variables. Add the following variables: MURAL_ACCESS_TOKEN: The OAuth access token obtained from the authorization flow. This is a long string that grants API access. MURAL_REFRESH_TOKEN: The refresh token used to obtain a new access token when the current one expires. Access tokens expire after about one hour. MURAL_CLIENT_ID: Your Mural application's Client ID from the developer portal. MURAL_CLIENT_SECRET: Your Mural application's Client Secret. This is used to refresh the access token. MURAL_WORKSPACE_ID: The ID of your Mural workspace. Find this in your Mural workspace URL — when you are viewing your workspace at app.mural.co/t/workspacename, the workspace ID is the 'workspacename' slug or a numeric ID depending on how Mural formats it. Do not add NEXT_PUBLIC_ to any of these — all Mural credentials are sensitive and must remain server-side only. After saving, trigger a redeployment. For local development, add all variables to .env.local.
Pro tip: Since Mural access tokens expire hourly, implement a token refresh strategy in your API route: attempt the request, and if you get a 401, use the refresh token to get a new access token, then retry the original request.
Expected result: Vercel Dashboard shows all Mural environment variables saved without NEXT_PUBLIC_ prefixes. After redeployment, your API route can authenticate with Mural.
Generate Your Mural Interface with V0
Generate Your Mural Interface with V0
Use V0 to generate the front-end components for your Mural integration. Since Mural is a visual tool, the most impactful interfaces are gallery views with thumbnail images, searchable mural lists, and activity feeds showing recent workshop sessions. For a mural gallery, ask V0 to generate a responsive card grid where each card represents one mural. Cards should show the mural title, a thumbnail image (using the thumbnail URL returned by the API), last modified date, and an 'Open in Mural' link. V0 can generate polished card designs with hover effects, loading skeletons, and empty states. For a workspace overview dashboard, ask V0 to generate a sidebar showing rooms (Mural's organizational folders) and a main content area showing the murals within the selected room. This hierarchy mirrors how Mural organizes content — workspace → rooms → murals. For embedding a specific Mural interactively, V0 can generate an iframe component similar to the Miro or Figma embed pattern. The Mural embed URL follows the format https://app.mural.co/embed/MURAL_ID. Add 'use client' to the component since iframe embeds run client-side. One V0 limitation to be aware of: V0 generates the component structure correctly but cannot validate that mural IDs are real or that thumbnails will load. Test with real IDs from your Mural workspace after generating the UI.
Build a mural workspace gallery that fetches from /api/mural/murals. Display murals in a 3-column responsive grid. Each card should show a thumbnail image with a gray placeholder background, the mural title in bold, a subtitle showing the room name, last modified date formatted as 'Updated 2 days ago', and an 'Open' button link. Add a search input at the top that filters cards by mural title.
Paste this in V0 chat
Pro tip: Ask V0 to include skeleton loading cards that match the dimensions of the real cards — this prevents layout shift when mural thumbnails load and gives a polished impression while the API fetches data.
Expected result: V0 generates a mural gallery or workspace dashboard with fetch calls to your API routes, card components with thumbnail placeholders, and search/filter functionality.
Create the Mural API Route
Create the Mural API Route
Build the server-side API route that fetches mural data from the Mural REST API. Create app/api/mural/route.ts. This route authenticates with your stored access token and returns workspace and mural data to your V0 components. Mural's API base URL is https://app.mural.co/api/public/v1. The key endpoints for a gallery use case are: GET /workspaces/{workspaceId}/murals to list all murals in a workspace, and GET /workspaces/{workspaceId}/rooms to list rooms within the workspace. Each mural response includes an id, title, thumbnailUrl (for displaying preview images), createdOn and updatedOn timestamps, and the room it belongs to. The thumbnailUrl is a direct image URL you can use in an img tag or Next.js Image component. Access token refresh is a critical part of production-ready Mural integration. If the stored access token has expired (after ~1 hour), the API returns a 401 error. Your route should catch this and use the refresh token flow to get a new access token before retrying. The token refresh endpoint is POST https://app.mural.co/api/public/v1/authorization/oauth2/token with the refresh_token grant type. For the token refresh to work in production, your API route needs to update the stored access token somewhere accessible for future requests. Since Vercel environment variables cannot be updated at runtime, a practical approach is to store the current access token in an external key-value store (like Upstash Redis or Vercel KV) that your API route reads from and writes to. This allows seamless token refresh without manual Vercel dashboard intervention.
Add a Next.js API route at app/api/mural/route.ts that uses the Mural v1 API. For GET requests, fetch all murals from the workspace ID in MURAL_WORKSPACE_ID using the Bearer token from MURAL_ACCESS_TOKEN. Return a JSON array with mural id, title, thumbnailUrl, createdOn, updatedOn, and roomId fields.
Paste this in V0 chat
1import { NextRequest, NextResponse } from 'next/server';23const MURAL_BASE_URL = 'https://app.mural.co/api/public/v1';45async function muralFetch(path: string, accessToken: string) {6 const response = await fetch(`${MURAL_BASE_URL}${path}`, {7 headers: {8 Authorization: `Bearer ${accessToken}`,9 Accept: 'application/json',10 },11 });1213 if (response.status === 401) {14 throw new Error('MURAL_TOKEN_EXPIRED');15 }1617 if (!response.ok) {18 throw new Error(`Mural API error: ${response.status} ${response.statusText}`);19 }2021 return response.json();22}2324async function refreshAccessToken(): Promise<string> {25 const response = await fetch(26 `${MURAL_BASE_URL}/authorization/oauth2/token`,27 {28 method: 'POST',29 headers: { 'Content-Type': 'application/x-www-form-urlencoded' },30 body: new URLSearchParams({31 grant_type: 'refresh_token',32 refresh_token: process.env.MURAL_REFRESH_TOKEN!,33 client_id: process.env.MURAL_CLIENT_ID!,34 client_secret: process.env.MURAL_CLIENT_SECRET!,35 }),36 }37 );3839 if (!response.ok) {40 throw new Error('Failed to refresh Mural access token');41 }4243 const data = await response.json();44 return data.access_token;45}4647export async function GET(request: NextRequest) {48 let accessToken = process.env.MURAL_ACCESS_TOKEN;49 const workspaceId = process.env.MURAL_WORKSPACE_ID;5051 if (!accessToken || !workspaceId) {52 return NextResponse.json(53 { error: 'Mural environment variables are not configured' },54 { status: 500 }55 );56 }5758 const { searchParams } = new URL(request.url);59 const roomId = searchParams.get('room');6061 try {62 let data;6364 try {65 const endpoint = roomId66 ? `/workspaces/${workspaceId}/rooms/${roomId}/murals`67 : `/workspaces/${workspaceId}/murals`;68 data = await muralFetch(endpoint, accessToken);69 } catch (error: unknown) {70 if (error instanceof Error && error.message === 'MURAL_TOKEN_EXPIRED') {71 // Refresh and retry once72 accessToken = await refreshAccessToken();73 const endpoint = roomId74 ? `/workspaces/${workspaceId}/rooms/${roomId}/murals`75 : `/workspaces/${workspaceId}/murals`;76 data = await muralFetch(endpoint, accessToken);77 } else {78 throw error;79 }80 }8182 const murals = (data.value || []).map((m: {83 id: string;84 title: string;85 thumbnailUrl?: string;86 createdOn: number;87 updatedOn: number;88 roomId?: string;89 }) => ({90 id: m.id,91 title: m.title || 'Untitled Mural',92 thumbnailUrl: m.thumbnailUrl || '',93 createdOn: new Date(m.createdOn).toISOString(),94 updatedOn: new Date(m.updatedOn).toISOString(),95 roomId: m.roomId || '',96 muralUrl: `https://app.mural.co/t/${workspaceId}/m/${m.id}`,97 }));9899 return NextResponse.json({ murals, total: murals.length });100 } catch (error: unknown) {101 console.error('Mural API error:', error);102 return NextResponse.json(103 { error: 'Failed to fetch Mural data' },104 { status: 500 }105 );106 }107}Pro tip: For production apps with frequent requests, store the refreshed access token in Upstash Redis so the refresh only happens when the token actually expires, not on every request.
Expected result: The API route returns a JSON array of murals with titles, thumbnail URLs, and timestamps. The V0-generated gallery renders mural cards with real data from your workspace.
Common use cases
Team Workspace Gallery Dashboard
A design team builds a V0 internal dashboard that lists all murals across their Mural workspace. Each mural card shows a thumbnail, creation date, the last modified time, and a direct link to open the mural. The dashboard fetches workspace data from a Next.js API route that queries Mural's workspace and murals endpoints.
Build a mural gallery dashboard that fetches from /api/mural/murals. Display murals in a responsive grid with cards showing a thumbnail placeholder, the mural title, last modified date, and an 'Open Mural' button. Include a search bar to filter by mural title and a sort dropdown for Recently Modified, Title A-Z, and Date Created.
Copy this prompt to try it in V0
Client Project Portal with Embedded Mural
An agency builds a client portal in V0 where clients can view the whiteboard from their project's discovery workshop session. The portal embeds the specific mural using an iframe and fetches the mural's metadata (title, last modified, facilitator) from the API to display alongside the embed.
Create a project workshop page that shows an embedded Mural whiteboard. Above the iframe, show the workshop title, facilitator name, and last updated date fetched from /api/mural/mural/:id. Below the iframe, add a note explaining that clients can add comments but cannot edit the template structure.
Copy this prompt to try it in V0
Sprint Retrospective Activity Tracker
An agile team builds a sprint tracking dashboard that lists all retrospective murals from Mural's recent activity. The dashboard shows which sprints have completed retros, links to the mural, and counts of sticky notes added — providing a historical log of team retrospective sessions.
Build a retrospectives tracker that fetches from /api/mural/rooms/retrospectives. Show a table listing each sprint retro with the mural title, date created, participant count, and a status badge (Active, Archived). Add a button next to each row to open the mural directly in Mural.
Copy this prompt to try it in V0
Troubleshooting
API route returns 401 Unauthorized from Mural
Cause: The stored access token has expired. Mural OAuth access tokens expire after approximately one hour of inactivity.
Solution: Implement the token refresh logic shown in the API route code. The refresh token has a much longer lifespan and can be used to obtain a new access token automatically. If both the access token and refresh token are expired, you will need to re-authorize the application manually in Mural's developer portal and update the environment variables.
1// Catch 401 and refresh before retrying2try {3 data = await muralFetch(endpoint, accessToken);4} catch (error) {5 if (error.message === 'MURAL_TOKEN_EXPIRED') {6 accessToken = await refreshAccessToken();7 data = await muralFetch(endpoint, accessToken); // retry8 }9}Mural thumbnails fail to load in the gallery (broken image icons)
Cause: Mural thumbnail URLs may be time-limited signed URLs that expire, or the thumbnailUrl field is null for newly created murals that have not been viewed yet.
Solution: Add an onError handler to your img elements that falls back to a placeholder image when thumbnails fail to load. For murals with empty thumbnailUrl, display a colored placeholder with the first letter of the mural title instead of attempting to load an image.
1<img2 src={mural.thumbnailUrl || '/placeholder-mural.svg'}3 alt={mural.title}4 onError={(e) => {5 (e.target as HTMLImageElement).src = '/placeholder-mural.svg';6 }}7 className="w-full h-32 object-cover rounded-t-lg"8/>Module not found: Can't resolve googleapis or mural-specific package
Cause: Mural does not have an official npm package — API calls must use the native fetch API or a generic HTTP client.
Solution: Use the native fetch API in your Mural API route rather than any external package. The Mural REST API accepts standard Bearer token authentication through the Authorization header. No npm package installation is required.
1// No npm package needed — use native fetch2const response = await fetch(`https://app.mural.co/api/public/v1/workspaces/${workspaceId}/murals`, {3 headers: {4 Authorization: `Bearer ${process.env.MURAL_ACCESS_TOKEN}`,5 Accept: 'application/json',6 },7});Best practices
- Implement OAuth token refresh logic in your API route to handle the one-hour access token expiry automatically without manual token rotation.
- Never expose MURAL_ACCESS_TOKEN, MURAL_REFRESH_TOKEN, or MURAL_CLIENT_SECRET with NEXT_PUBLIC_ prefixes — all Mural credentials are sensitive.
- Cache the mural list response for at least 5 minutes — mural data changes infrequently and caching reduces API calls and improves dashboard performance.
- Add fallback placeholder images for murals with missing thumbnailUrl values using an onError handler on img elements.
- Link directly to murals using their mural URL (https://app.mural.co/t/{workspaceId}/m/{muralId}) rather than embedding when interactivity is not needed.
- Store refreshed access tokens in an external key-value store like Upstash Redis rather than Vercel environment variables, which cannot be updated at runtime.
- Test your integration with a mural you can edit to verify read and potential write operations before building the complete UI.
- Use Mural's room structure to scope your API fetches — fetching murals by room is faster and more focused than fetching all workspace murals.
Alternatives
Miro is an alternative if you need broader visual collaboration with a richer API, official React SDK, and stronger developer tooling — Miro's integrations ecosystem is larger than Mural's.
Lucidchart is an alternative if your whiteboard use case is primarily diagramming (flowcharts, architecture diagrams, org charts) rather than facilitation-focused workshops.
Notion is an alternative for lightweight visual organization and collaborative documentation when you do not need dedicated whiteboard facilitation features.
Frequently asked questions
Does V0 have a native Mural integration?
No, V0 does not have a one-click Mural integration through the Vercel Marketplace. You need to set up OAuth credentials and build a Next.js API route using Mural's REST API. V0 can generate the gallery UI and API route boilerplate when you describe the integration in the V0 chat.
Can I embed an interactive Mural whiteboard in a V0-generated page?
Yes, Mural supports iframe embedding. The embed URL format is https://app.mural.co/embed/{muralId}. Create a client component in your V0 project with 'use client' at the top and render an iframe with that URL. Note that embedded Mural whiteboards require viewers to have a Mural account to interact with the content, though they can view without an account in some configurations.
What is the difference between Mural and Miro?
Mural focuses specifically on structured facilitation — guided workshops, retrospectives, and team exercises with templates designed for specific outcomes. Miro is a broader visual collaboration tool with stronger developer tooling, a richer API, and more integrations. For workshop-heavy teams, Mural's facilitation features are superior; for general visual collaboration and diagramming, Miro has advantages. For V0 integrations, Miro's API and SDK are generally more developer-friendly.
How do I display only murals from a specific Mural room?
Pass the room ID as a query parameter to your API route (e.g., /api/mural/murals?room=ROOM_ID). In the API route, use the /workspaces/{workspaceId}/rooms/{roomId}/murals endpoint instead of the workspace-level murals endpoint. First fetch the list of rooms from /workspaces/{workspaceId}/rooms to get room IDs, then filter murals by room.
Does my Mural plan include API access?
Mural API access availability depends on your subscription plan. Enterprise plans typically include full API access. Team plans may have limited or no API access. Check your Mural admin settings under Integrations or contact Mural support to confirm API availability on your current plan. The developer portal at developers.mural.co shows the API capabilities for your account.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation