To integrate Zendesk Sunshine Conversations (formerly Smooch) with V0 by Vercel, generate a chat UI in V0, create a Next.js API route that uses the Sunshine Conversations REST API to send and receive messages across web, SMS, and WhatsApp channels, and add your Sunshine Conversations credentials as Vercel environment variables. Your V0 app will support true omnichannel customer messaging.
Add Omnichannel Customer Messaging to Your V0-Built App
Zendesk Sunshine Conversations (originally called Smooch before Zendesk acquired it in 2019) is a powerful omnichannel messaging API that lets you build customer communication experiences spanning web chat, SMS, WhatsApp, Facebook Messenger, and more — all through a single unified API. For companies building customer-facing apps with V0 and Next.js, it provides a professional messaging infrastructure without having to build separate integrations for each channel.
The integration architecture has two main components. First, the Sunshine Conversations web widget or SDK can be embedded directly in your V0-generated Next.js app, giving web visitors a branded chat interface that connects to your support team through Zendesk. Second, the Sunshine Conversations REST API lets your server-side Next.js code programmatically send messages, create conversations, and manage users — enabling automated notifications, proactive outreach, and custom messaging workflows.
This is particularly valuable for SaaS products, marketplaces, and service businesses that need to meet customers on their preferred messaging channels while maintaining a unified conversation history and agent workspace. Unlike building separate integrations for each channel, Sunshine Conversations normalizes the data model — every message, regardless of channel origin, looks the same in your code and in the Zendesk agent interface.
Integration method
Sunshine Conversations provides a REST API for creating conversations, sending messages, and managing channel connections. V0 generates the frontend chat UI and customer-facing messaging interface, while Next.js API routes proxy all Sunshine Conversations API calls to keep your App ID and API key secret. Incoming messages from customers on any channel (SMS, WhatsApp, web widget) can be received via webhooks and relayed to your app in real time.
Prerequisites
- A V0 account at v0.dev and a Vercel account for deployment
- A Zendesk account with Sunshine Conversations enabled — available on Zendesk Suite Professional plans or as an add-on
- Your Sunshine Conversations App ID and API key pair — generated in the Sunshine Conversations dashboard under Settings → API Keys
- Familiarity with webhooks if you plan to receive incoming messages from customers in real time
- Basic understanding of copying TypeScript code snippets and setting environment variables in the Vercel Dashboard
Step-by-step guide
Generate the Chat UI in V0
Generate the Chat UI in V0
Start by having V0 generate the customer-facing chat interface for your app. Whether you want a floating chat widget, an embedded full-page messaging view, or a support button that reveals a slide-in panel, V0 can generate the React component with all the necessary visual elements. Be specific about what the experience should look like: the chat bubble position, the panel dimensions, message bubble styles, timestamp display, typing indicators, and the overall color scheme. For a customer support chat, describe the full interaction flow: what the user sees before they start chatting (a greeting message, suggested questions), the message thread with distinct user vs. agent bubble styles, the text input with an emoji button and file attachment option, and the header showing agent name and online status. The more specific you are, the less iteration you'll need. At this stage, V0 will generate the component with hardcoded mock messages and no real API connection. This is correct — you're designing the experience before wiring up the backend. Use V0's preview and Design Mode to get the layout exactly right, then deploy to Vercel to get your live URL before proceeding to configure the Sunshine Conversations credentials.
Create a floating customer support chat widget for the bottom-right corner of the page. The collapsed state shows a blue chat bubble button with a notification badge. When clicked, expand to show a 300x480px chat panel with: a header with agent avatar, name 'Support Team', and a green online dot; a message list area with alternating user messages (right-aligned, blue bubbles) and agent messages (left-aligned, gray bubbles); timestamps under each message; and a footer with a text input, emoji button, and send button. Fetch messages from /api/chat/messages and post new messages to /api/chat/send. Include smooth open/close animation.
Paste this in V0 chat
Pro tip: Design the unread message notification badge count to be driven by a state variable you can update from the API response. This lets you show customers how many new messages they have without them opening the widget.
Expected result: V0 generates a polished chat widget component with mock messages, smooth animations, and all UI elements deployed to a live Vercel URL.
Set Up Your Sunshine Conversations App and Generate API Credentials
Set Up Your Sunshine Conversations App and Generate API Credentials
Before writing any integration code, you need to configure your Sunshine Conversations app and generate the API credentials that authenticate your Next.js server with the Sunshine Conversations platform. Log in to your Zendesk account and navigate to Sunshine Conversations (also accessible directly at app.smooch.io if you have a legacy Smooch account). In the Sunshine Conversations dashboard, create a new App or select your existing app. Navigate to Settings → API Keys and click 'Create API Key'. Give the key a descriptive name like 'V0 Next.js Integration'. Sunshine Conversations generates two values: an App ID (also called keyId) and a Secret. Copy both values immediately and store them securely — the secret is only shown once. Also note your Sunshine Conversations App ID from the app settings — this is a separate identifier from the API key ID. You'll need three values total: the App ID (for identifying which app's conversations you're working with), the API Key ID, and the API Key Secret. The App ID is visible in the app settings URL and dashboard header. For the web widget, you'll also want to note your Integration ID (found under Integrations → Web Messenger) — this is the value you pass to the Sunshine Conversations Web SDK to initialize the widget in the browser.
Pro tip: Create a dedicated API key specifically for your V0 Next.js app rather than reusing an existing key. This way, if you ever need to revoke access or rotate credentials for this specific integration, you can do so without affecting other services that use Sunshine Conversations.
Expected result: You have three credential values noted securely: Sunshine Conversations App ID, API Key ID, and API Key Secret, ready to add as Vercel environment variables.
Create Next.js API Routes for Sending and Receiving Messages
Create Next.js API Routes for Sending and Receiving Messages
Create the server-side API routes that will proxy all Sunshine Conversations API calls. You need at minimum two routes: one to send messages from your app to a customer conversation, and one to fetch conversation history. These routes run on Vercel's serverless infrastructure, keeping your API credentials server-side. The Sunshine Conversations API base URL is https://api.smooch.io/v2/apps/{appId}/. Authentication uses HTTP Basic Auth with your API Key ID as the username and API Key Secret as the password — these are passed as a Base64-encoded Authorization header. For sending a message, POST to /v2/apps/{appId}/conversations/{conversationId}/messages with the message content and author details in the request body. For fetching messages, GET /v2/apps/{appId}/conversations/{conversationId}/messages. For real-time incoming messages from customers on external channels (SMS, WhatsApp), you'll need a webhook endpoint. Create a route at /api/chat/webhook that receives POST requests from Sunshine Conversations when new messages arrive. Sunshine Conversations sends a signature header (X-Api-Key) that you should validate to confirm the webhook is genuinely from Sunshine Conversations and not a spoofed request. Store the webhook secret in an environment variable and verify it on every incoming request.
1// app/api/chat/send/route.ts2import { NextResponse } from 'next/server';34const SMOOCH_API_BASE = 'https://api.smooch.io/v2';56function getAuthHeader() {7 const keyId = process.env.SUNSHINE_API_KEY_ID!;8 const secret = process.env.SUNSHINE_API_KEY_SECRET!;9 return 'Basic ' + Buffer.from(`${keyId}:${secret}`).toString('base64');10}1112export async function POST(request: Request) {13 const appId = process.env.SUNSHINE_APP_ID;1415 if (!appId || !process.env.SUNSHINE_API_KEY_ID || !process.env.SUNSHINE_API_KEY_SECRET) {16 return NextResponse.json({ error: 'Sunshine Conversations not configured' }, { status: 500 });17 }1819 const { conversationId, text, authorId, authorName } = await request.json();2021 if (!conversationId || !text) {22 return NextResponse.json({ error: 'conversationId and text are required' }, { status: 400 });23 }2425 try {26 const response = await fetch(27 `${SMOOCH_API_BASE}/apps/${appId}/conversations/${conversationId}/messages`,28 {29 method: 'POST',30 headers: {31 Authorization: getAuthHeader(),32 'Content-Type': 'application/json',33 },34 body: JSON.stringify({35 author: {36 type: 'business',37 userId: authorId || 'system',38 displayName: authorName || 'Support Team',39 },40 content: {41 type: 'text',42 text,43 },44 }),45 }46 );4748 if (!response.ok) {49 const errorText = await response.text();50 console.error('Sunshine API error:', response.status, errorText);51 return NextResponse.json({ error: `API returned ${response.status}` }, { status: response.status });52 }5354 const data = await response.json();55 return NextResponse.json({ message: data.message });56 } catch (error) {57 console.error('Failed to send message:', error);58 return NextResponse.json({ error: 'Failed to send message' }, { status: 500 });59 }60}6162// app/api/chat/messages/route.ts63// GET conversation messages64export async function GET_MESSAGES(request: Request) {65 const { searchParams } = new URL(request.url);66 const conversationId = searchParams.get('conversationId');67 const appId = process.env.SUNSHINE_APP_ID;6869 if (!conversationId) {70 return NextResponse.json({ error: 'conversationId is required' }, { status: 400 });71 }7273 const response = await fetch(74 `${SMOOCH_API_BASE}/apps/${appId}/conversations/${conversationId}/messages`,75 {76 headers: { Authorization: getAuthHeader() },77 next: { revalidate: 0 }, // Always fresh for chat messages78 }79 );8081 const data = await response.json();82 return NextResponse.json({ messages: data.messages || [] });83}Pro tip: For the messages GET route, set next: { revalidate: 0 } to disable caching entirely — chat messages must always be fetched fresh. Caching is appropriate for slow-changing data like product listings, but never for real-time messages.
Expected result: API routes exist at /api/chat/send and /api/chat/messages and return appropriate responses when tested with the correct credentials.
Add Sunshine Conversations Credentials to Vercel Environment Variables
Add Sunshine Conversations Credentials to Vercel Environment Variables
With your API routes written, configure the environment variables your Vercel deployment needs to authenticate with Sunshine Conversations. Open the Vercel Dashboard at vercel.com, navigate to your project, and click Settings → Environment Variables. You'll add four variables: SUNSHINE_APP_ID (your Sunshine Conversations App ID from the dashboard), SUNSHINE_API_KEY_ID (the key ID from the API key you created), SUNSHINE_API_KEY_SECRET (the secret from the API key — only shown once, so use what you saved in Step 2), and optionally SUNSHINE_WEBHOOK_SECRET if you're implementing the webhook endpoint for incoming messages. For each variable, select both Production and Preview environments so both your live site and Vercel preview deployments work correctly. Never add NEXT_PUBLIC_ prefix to these variables — they contain sensitive secrets that must stay server-side only and should never be accessible in the browser. After adding all variables, trigger a redeployment by pushing a commit to GitHub or clicking Redeploy in the Vercel Dashboard. Once the deployment completes, test your API routes directly in the browser to confirm authentication works.
Pro tip: If you're setting up the web widget, you'll also need NEXT_PUBLIC_SUNSHINE_INTEGRATION_ID — this is the web widget integration ID that's safe to expose in the browser since it's not a secret key. It goes in your Next.js script tag that initializes the Sunshine web widget.
Expected result: All four Sunshine Conversations environment variables are set in Vercel, and a fresh deployment confirms the API routes authenticate and respond correctly.
Embed the Web Widget and Test the Full Messaging Flow
Embed the Web Widget and Test the Full Messaging Flow
The final step connects everything together: embedding the Sunshine Conversations web widget in your Next.js app so customers can initiate conversations from your website, and verifying that messages flow correctly between your app, Sunshine Conversations, and your Zendesk agent workspace. For the web widget approach, add the Sunshine Conversations Web SDK script to your Next.js layout. In app/layout.tsx, use Next.js's Script component to load the Sunshine SDK from their CDN and initialize it with your Integration ID. Once initialized, the SDK creates the chat widget automatically — customers who click it start a web conversation that appears in Zendesk. For the custom chat UI approach (using your V0-generated chat component), you need to create a conversation ID for each user and persist it in localStorage or a database. When a user first opens the chat, call a route that creates a new Sunshine Conversations conversation and returns the conversation ID. Store this ID in the browser and include it in subsequent message API calls to maintain conversation continuity across page loads. Test the complete flow: open your deployed app, send a test message through the chat widget or your custom UI, verify it appears in the Sunshine Conversations dashboard and Zendesk, then reply from Zendesk and confirm the reply appears in your app. For complex omnichannel setups requiring SMS or WhatsApp channel configuration, RapidDev's team can help integrate those channel-specific APIs into your Sunshine Conversations workspace.
Update the chat widget to initialize a conversation on first open by calling /api/chat/create-conversation if there's no conversationId in localStorage. Store the returned conversationId in localStorage. Poll /api/chat/messages?conversationId={id} every 5 seconds to check for new messages and update the message list. When the user sends a message, POST to /api/chat/send with the conversationId and message text. Show a subtle 'Connecting...' state while the conversation is being created.
Paste this in V0 chat
1// app/layout.tsx - Add Sunshine web widget2import Script from 'next/script';34// Inside your layout's <body>:5// <Script6// id="sunshine-conversations"7// strategy="afterInteractive"8// dangerouslySetInnerHTML={{9// __html: `10// !function(o,p,s,e,c){11// var i,a,h,u=[],d=[];12// function t(){var t=p.createElement("script");t.async=!0,t.crossOrigin="anonymous",13// t.src="https://cdn.smooch.io/smooch.min.js",14// (a=p.getElementsByTagName("script")[0]).parentNode.insertBefore(t,a)15// }16// // Initialize Sunshine widget17// Smooch.init({ integrationId: '${process.env.NEXT_PUBLIC_SUNSHINE_INTEGRATION_ID}' })18// `19// }}20// />2122// app/api/chat/create-conversation/route.ts23import { NextResponse } from 'next/server';2425export async function POST(request: Request) {26 const appId = process.env.SUNSHINE_APP_ID;27 const keyId = process.env.SUNSHINE_API_KEY_ID!;28 const secret = process.env.SUNSHINE_API_KEY_SECRET!;29 const authHeader = 'Basic ' + Buffer.from(`${keyId}:${secret}`).toString('base64');3031 const { userId, displayName } = await request.json();3233 try {34 // First, create or get the user35 const userRes = await fetch(36 `https://api.smooch.io/v2/apps/${appId}/users`,37 {38 method: 'POST',39 headers: { Authorization: authHeader, 'Content-Type': 'application/json' },40 body: JSON.stringify({ userId, profile: { displayName } }),41 }42 );4344 // Create a conversation for the user45 const convRes = await fetch(46 `https://api.smooch.io/v2/apps/${appId}/conversations`,47 {48 method: 'POST',49 headers: { Authorization: authHeader, 'Content-Type': 'application/json' },50 body: JSON.stringify({51 type: 'personal',52 participants: [{ userId, subscribeTo: ['*'] }],53 }),54 }55 );5657 const conv = await convRes.json();58 return NextResponse.json({ conversationId: conv.conversation?.id });59 } catch (error) {60 return NextResponse.json({ error: 'Failed to create conversation' }, { status: 500 });61 }62}Pro tip: For production, poll for new messages every 5-10 seconds on the client side. For lower latency, consider upgrading to Sunshine Conversations webhooks — your server receives an event the instant a new message arrives and can push it to the browser via Server-Sent Events or a WebSocket connection.
Expected result: Customers can open the chat widget on your deployed V0 app, send messages, and receive replies — with all conversations tracked in your Zendesk workspace across web, SMS, and WhatsApp channels.
Common use cases
Embedded Web Chat Widget on V0 App
Add Sunshine Conversations' branded web messenger to your Next.js app so website visitors can start a chat that appears in your Zendesk agent workspace. The widget supports file sharing, typing indicators, and conversation history. When visitors return, they see their previous conversation, creating a continuous support experience across sessions.
Add a customer support chat widget to the bottom-right corner of my app. When the user clicks a blue chat bubble icon, slide up a chat panel showing conversation history fetched from /api/chat/messages. Include a text input at the bottom and a send button. The panel header should show 'Support Chat' and a green 'Online' status indicator. Make the widget match our brand with a navy blue color scheme.
Copy this prompt to try it in V0
Automated Order Status Notifications via WhatsApp and SMS
When a customer places an order or reaches a status milestone in your app, automatically send them a notification on their preferred channel — WhatsApp or SMS — via the Sunshine Conversations API. The message is sent server-side from a Next.js API route triggered by your order processing logic, maintaining a unified conversation thread they can reply to.
Create an order confirmation page that, after a successful checkout, calls /api/messaging/notify with the customer's phone number and order ID. Show a success banner that says 'We sent you a WhatsApp confirmation!' and display the order summary. Include a 'Chat with Support' button that opens the messaging widget if they have questions.
Copy this prompt to try it in V0
Multi-Channel Customer Intake Form with Conversation Routing
A lead intake form that creates a Sunshine Conversations user profile and conversation when submitted, then routes the conversation to the right team based on the inquiry type. A new business inquiry goes to the sales team's Zendesk queue while a support issue goes to the technical support queue — all tracked as unified customer profiles.
Build a contact form with fields for name, email, phone number, inquiry type (dropdown: Sales, Support, Partnership), and message. On submit, call /api/conversations/create. Show a confirmation step that tells the user they'll receive a reply via their chosen channel with an estimated response time. Use a clean, professional layout with form validation.
Copy this prompt to try it in V0
Troubleshooting
API routes return 401 Unauthorized when calling the Sunshine Conversations API
Cause: The API Key ID or Secret is incorrect, the Basic Auth header is being constructed incorrectly, or the environment variables haven't been deployed yet. Sunshine Conversations Basic Auth requires Base64-encoding of keyId:secret.
Solution: Verify the auth header construction: the format must be 'Basic ' followed by the Base64 encoding of 'API_KEY_ID:API_KEY_SECRET'. Check that both SUNSHINE_API_KEY_ID and SUNSHINE_API_KEY_SECRET are set in Vercel with the correct values, and that you've redeployed after adding the variables.
1// Test your auth header construction locally2const keyId = 'your_key_id';3const secret = 'your_secret';4const auth = 'Basic ' + Buffer.from(`${keyId}:${secret}`).toString('base64');5console.log(auth); // Should be 'Basic <base64string>'Chat messages sent from the app don't appear in the Zendesk agent workspace
Cause: The App ID in your environment variables may not match the Sunshine Conversations app connected to your Zendesk workspace, or the conversation was created for a different app than the one linked to Zendesk.
Solution: Verify that SUNSHINE_APP_ID matches the App ID of the Sunshine Conversations integration connected to your Zendesk instance. In the Sunshine Conversations dashboard, go to Integrations and confirm the app is linked to your Zendesk account. Messages only appear in Zendesk for apps that have the Zendesk integration enabled.
Web widget doesn't appear on the page after adding the Sunshine script
Cause: The NEXT_PUBLIC_SUNSHINE_INTEGRATION_ID is missing or incorrect, the script is loading before the DOM is ready, or a Content Security Policy (CSP) header is blocking the Sunshine SDK CDN.
Solution: Confirm NEXT_PUBLIC_SUNSHINE_INTEGRATION_ID is set with the NEXT_PUBLIC_ prefix (since it's needed in the browser). Check the browser console for CSP errors or 404 errors loading the Sunshine SDK. Ensure the Script component uses strategy='afterInteractive' to load after the page is interactive.
1// In app/layout.tsx - ensure correct Script strategy2import Script from 'next/script';3// Use strategy='afterInteractive' not 'beforeInteractive'4// <Script strategy="afterInteractive" src="..." />Webhook endpoint returns 403 or webhook events aren't being received
Cause: The webhook URL isn't registered in the Sunshine Conversations dashboard, the webhook secret validation is failing, or Vercel is blocking the incoming webhook POST requests.
Solution: Register your webhook URL (https://your-app.vercel.app/api/chat/webhook) in the Sunshine Conversations dashboard under Settings → Webhooks. Ensure your webhook route handles POST requests without CSRF protection (Next.js App Router routes don't have CSRF by default, so this should work). Verify the webhook secret matches your SUNSHINE_WEBHOOK_SECRET environment variable.
Best practices
- Always proxy Sunshine Conversations API calls through Next.js API routes — never call the Sunshine API directly from client-side components, as this would expose your API key and secret in the browser.
- Use HTTP Basic Auth with Base64-encoded key ID and secret for Sunshine Conversations API authentication — construct this header server-side in a shared utility function to avoid repetition across routes.
- Set next: { revalidate: 0 } on all chat message fetch calls to disable caching — chat data must always be fresh and never served from a stale cache.
- Persist conversation IDs in your database (Neon or Supabase) tied to user accounts rather than localStorage — this enables customers to continue conversations across devices and after clearing browser data.
- Validate webhook signatures on every incoming Sunshine Conversations webhook to prevent spoofed requests from injecting fake messages into your system.
- Store SUNSHINE_APP_ID, SUNSHINE_API_KEY_ID, and SUNSHINE_API_KEY_SECRET as server-only environment variables (no NEXT_PUBLIC_ prefix) — these are sensitive credentials that must never reach the browser.
- Use NEXT_PUBLIC_SUNSHINE_INTEGRATION_ID only for the web widget initialization script, since the integration ID is not a secret and must be accessible in the browser to load the widget.
- Implement proper error handling in your chat UI — if a message fails to send (network error, API outage), show a retry button rather than silently dropping the message.
Alternatives
Choose Flock if you need internal team messaging and notifications for your app rather than customer-facing omnichannel support — Flock is designed for team collaboration, not external customer conversations.
Choose Microsoft Teams integration if your organization is deeply invested in the Microsoft 365 ecosystem and needs to route customer or internal notifications through Teams channels rather than a standalone messaging platform.
Frequently asked questions
What is the difference between Smooch and Zendesk Sunshine Conversations?
Smooch was the original company name — Zendesk acquired Smooch in 2019 and rebranded it as Zendesk Sunshine Conversations. The underlying API and platform are the same product. The API domain remains api.smooch.io and the web widget SDK is still called Smooch. For all practical purposes, Smooch and Sunshine Conversations refer to the same platform.
Do I need a full Zendesk subscription to use Sunshine Conversations?
Yes, Sunshine Conversations is a Zendesk product and requires an active Zendesk account. It's available on Zendesk Suite Professional and Enterprise plans, or as a standalone add-on. The Sunshine Conversations API pricing is based on monthly active users (MAUs) — contacts who send or receive at least one message in a calendar month. Check Zendesk's current pricing page for the exact MAU tier rates.
Can I use Sunshine Conversations to send WhatsApp messages from my V0 app?
Yes, this is one of Sunshine Conversations' core features. To enable WhatsApp, you need to configure a WhatsApp Business API channel in the Sunshine Conversations dashboard — this requires a WhatsApp Business Account and Meta API access. Once the channel is connected, messages sent to a conversation where the user's WhatsApp channel is linked will automatically be delivered via WhatsApp. Your Next.js API routes don't need to change — the channel routing is handled by Sunshine Conversations.
How do I show unread message counts in the chat widget badge?
Poll your /api/chat/messages endpoint periodically and compare the latest message timestamp against the last-read timestamp stored in localStorage. The count of messages newer than the last-read timestamp is your unread count. Update the badge in your React component's state when this count changes. The Sunshine Conversations Web SDK also has built-in unread count handling if you use the native widget rather than a custom UI.
Is the Sunshine Conversations web widget accessible on mobile?
Yes, the Sunshine Conversations Web SDK widget is fully responsive and works on mobile browsers. It adapts to screen size automatically. If you've built a custom chat UI with V0, you'll need to ensure your component is responsive with Tailwind's responsive prefixes (sm:, md:) and that the floating widget doesn't interfere with mobile navigation elements.
Can I use Sunshine Conversations without Zendesk — just as a standalone messaging API?
The Sunshine Conversations platform was originally standalone (as Smooch), but since the Zendesk acquisition it's primarily positioned as part of the Zendesk ecosystem. You can use the API programmatically for sending/receiving messages without the Zendesk agent interface, but you'll still need a Zendesk account for billing and access. If you want a truly standalone messaging API without Zendesk dependency, consider alternatives like Twilio's Conversations API.
How do I test the webhook integration locally before deploying to Vercel?
Use ngrok (ngrok.com) to create a public HTTPS tunnel to your local Next.js development server. Run ngrok http 3000 to get a public URL like https://abc123.ngrok.io, then register https://abc123.ngrok.io/api/chat/webhook in the Sunshine Conversations dashboard as your webhook URL for testing. Send a test message in the Sunshine Conversations dashboard and verify your local webhook handler receives it.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation