We build custom applications 5x faster and cheaper 🚀
Book a Free Consultation
Stuck on an error? Book a 30-minute call with an engineer and get a direct fix + next steps. No pressure, no commitment.
Replit can integrate directly with Zendesk Sunshine Conversations (formerly Smooch) through its REST API and webhooks. You’ll run a Node.js (or Python) web server inside a Repl that connects to Smooch via HTTPS requests. Your Repl server receives messages from users through a webhook configured in Sunshine Conversations, processes them, and replies by calling Smooch’s API with valid credentials. The connection uses an OAuth or Service Account key, stored safely as a Replit Secret (environment variable), not hardcoded. Once your Repl is running, the exposed port (usually 3000) is publicly available, making webhook callbacks from Sunshine Conversations possible without additional tunneling tools.
The flow is straightforward but explicit:
sunshine-conversations-client, or you can work directly through axios for raw REST calls.https://<your-repl-name>.<your-username>.repl.co.
This example shows how to set up a minimal Repl server that connects to Sunshine Conversations using the REST API. It listens for incoming messages and sends a simple automated reply back through the Smooch API.
// Load required packages
import express from "express"
import bodyParser from "body-parser"
import axios from "axios"
const app = express()
app.use(bodyParser.json())
// Read credentials from Replit Secrets (Environment Variables)
const { SMOOCH_APP_ID, SMOOCH_KEY_ID, SMOOCH_SECRET } = process.env
// Sunshine Conversations API base
const SMOOCH_BASE_URL = `https://api.smooch.io/v2/apps/${SMOOCH_APP_ID}`
// Build the Basic Auth header from key_id and secret
const authHeader = "Basic " + Buffer.from(`${SMOOCH_KEY_ID}:${SMOOCH_SECRET}`).toString("base64")
// Route to handle webhook messages from Smooch
app.post("/webhook", async (req, res) => {
console.log("Webhook received:", req.body)
// Extract the message text if available
const message = req.body.messages && req.body.messages[0]
if (message && message.text) {
const userId = message.author.userId
// Compose a reply message back to the same user
await axios.post(
`${SMOOCH_BASE_URL}/messages`,
{
author: { type: "business" },
content: { type: "text", text: `You said: ${message.text}` },
destination: { type: "user", userId }
},
{ headers: { Authorization: authHeader, "Content-Type": "application/json" } }
)
}
res.sendStatus(200)
})
// Start the server on port 3000 and bind to 0.0.0.0 for Replit
app.listen(3000, "0.0.0.0", () => console.log("Repl listening on port 3000"))
Once your Repl is live, you must tell Sunshine Conversations where to deliver webhook events. Run a one-time API call using your credentials:
curl -X POST "https://api.smooch.io/v2/apps/$SMOOCH_APP_ID/webhooks" \
-u "$SMOOCH_KEY_ID:$SMOOCH_SECRET" \
-H "Content-Type: application/json" \
-d '{
"target": "https://your-repl-name.your-username.repl.co/webhook",
"triggers": ["message:appUser"]
}'
That’s the full working model: explicit REST calls, real endpoints, correct authentication, and an endpoint bound to 0.0.0.0 so Replit’s network proxy can expose your Sunshine Conversations integration publicly and safely.
1
Build and host a chatbot service directly inside Replit that connects Sunshine Conversations (formerly Smooch) to a custom logic API. When a user sends a message through a channel (like WhatsApp, Messenger, or your website widget), Sunshine triggers a webhook. Your Repl receives this webhook on a bound port (for example, 0.0.0.0:8000) and processes it live. You manage the Zendesk app and secret keys with Replit Secrets so they remain secure across sessions. The chat logic, such as generating automated replies or integrating with OpenAI’s API, runs inside the Repl runtime. Replit Workflows let you restart or test the service automatically when code changes. This use case turns Replit into a lightweight, cloud-based chat processor without deploying external servers.
import express from "express"
import fetch from "node-fetch"
const app = express()
app.use(express.json())
app.post("/webhook", async (req, res) => {
const msg = req.body.messages?.[0]
if (msg?.text) {
await fetch("https://api.smooch.io/v2/apps/YOUR_APP_ID/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.ZENDESK_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
author: { type: "business" },
text: `You said: ${msg.text}`
})
})
}
res.sendStatus(200)
})
app.listen(8000, "0.0.0.0", () => console.log("Webhook listening"))
2
Use Replit as a quick sandboxed environment to experiment with support dashboards that query Sunshine Conversations’ REST API. An agent-facing dashboard (built with HTML/JS inside a Repl) can list active conversations, display message histories, and let staff send responses. This prototype mirrors the logic of a full enterprise environment without deploying it permanently. Because Replit runs both client (static HTML files) and backend (Express/Node) in one workspace, you can fetch data securely through your backend using stored credentials. This setup helps new developers or non-tech operators visualize and test integrations safely before moving to a production Zendesk environment.
import express from "express"
import fetch from "node-fetch"
const app = express()
app.get("/conversations", async (req, res) => {
const resp = await fetch("https://api.smooch.io/v2/apps/YOUR_APP_ID/conversations", {
headers: { "Authorization": `Bearer ${process.env.ZENDESK_API_KEY}` }
})
const data = await resp.json()
res.json(data)
})
app.listen(8000, "0.0.0.0")
3
Create a Webhook verification sandbox in Replit for Sunshine Conversations to validate real message events and signatures safely. You expose a public port through Replit’s live URL (e.g., https://your-repl-name.your-username.repl.co/webhook) and configure it in Zendesk as the webhook endpoint. When new messages or delivery receipts arrive, you log events in Replit’s console and verify authenticity using HMAC signatures from the header. This lets developers confirm their webhook signing process, event structure, and rate handling before pushing the code into a production server or cloud function.
import crypto from "crypto"
import express from "express"
const app = express()
app.use(express.json({ verify: (req, res, buf) => (req.rawBody = buf) }))
app.post("/webhook", (req, res) => {
const sig = req.headers["x-smooch-signature"]
const hash = crypto
.createHmac("sha256", process.env.ZENDESK_WEBHOOK_SECRET)
.update(req.rawBody)
.digest("hex")
if (sig !== hash) return res.status(401).send("Invalid signature")
console.log("Valid event:", JSON.stringify(req.body, null, 2))
res.sendStatus(200)
})
app.listen(8000, "0.0.0.0", () => console.log("Verifier active"))
Speak one‑on‑one with a senior engineer about your no‑code app, migration goals, and budget. In just half an hour you’ll leave with clear, actionable next steps—no strings attached.
1
The Smooch (Zendesk Sunshine Conversations) webhook isn’t receiving messages because the Replit server URL is not publicly reachable in the persistent way the webhook service expects. Replit gives you a temporary HTTPS URL only while your Repl is running. Once the Repl sleeps or restarts, the URL changes, and the webhook endpoint breaks. Additionally, Sunshine Conversations requires a valid HTTPS endpoint that responds with HTTP 2xx quickly — if your app is bound incorrectly (not to 0.0.0.0 or wrong port), or not handling POST JSON body properly, the messages fail silently.
Ensure your Express (or any HTTP) server binds to 0.0.0.0 and listens on the Replit-assigned PORT. Use Replit Secrets for your API tokens. Then, copy the current public URL from Replit’s “Webview” button and configure it in the Sunshine Conversations dashboard webhook settings.
import express from "express"
const app = express()
app.use(express.json())
app.post("/webhook", (req,res)=>{
console.log(req.body) // log incoming webhook data
res.sendStatus(200) // respond fast with 200 OK
})
app.listen(process.env.PORT, "0.0.0.0", ()=>{
console.log("Server running on", process.env.PORT)
})
Once working, migrate the same code to a stable hosting (like a deployment or external server) for production webhooks.
2
To correctly set Smooch (Sunshine Conversations) API keys in Replit, store them as Secrets so they become environment variables accessible only by your running code. Open the “Secrets” tab in Replit (🔑 icon on left panel), add a key name like SMOOCH_APP_ID and another for SMOOCH_API_KEY, then reference them in your code through process.env. This keeps credentials safe and ensures they persist across restarts without exposing them in your code.
Replit’s Secrets manager securely injects key/value pairs into the runtime environment. They act as temporary environment variables visible only to your Repl. Once you define your Smooch credentials there, they automatically load whenever your app starts — no file configuration needed. You simply call them via Node.js process environment access. Never commit raw credentials to your repository; Replit automatically masks their values in logs or console output.
// Example Node.js usage inside index.js
const appId = process.env.SMOOCH_APP_ID
const apiKey = process.env.SMOOCH_API_KEY
console.log("Using Smooch App:", appId)
// Initialize client using official SDK or REST calls with Authorization header
3
The Replit server URL doesn’t stay active for Smooch webhook requests because Replit free-hosted Repls enter “sleep” mode or restart when inactive. When this happens, the temporary preview URL (the one ending with replit.app or repl.co) is deactivated, and no background process remains to keep your server listening for incoming requests. Webhooks require a constant, publicly reachable endpoint, but Replit containers stop running once you close the tab or stop the Repl.
When you run Express or another web framework, it only responds while the Repl runtime stays awake. Once idle, the container shuts down to free resources. That’s why the webhook sender (like Smooch) gets “connection refused” or “timeout” errors — it can’t reach your temporary URL anymore.
app.listen(3000, '0.0.0.0') so the Repl exposes the correct port.
import express from "express"
const app = express()
app.post("/webhook", (req, res) => {
console.log("Webhook received!")
res.sendStatus(200)
})
// Bind to 0.0.0.0 so Replit maps port externally
app.listen(3000, "0.0.0.0", () => console.log("Server running"))
Sunshine Conversations (formerly Smooch) pushes webhook events — like new messages — to your app’s public endpoint. On Replit, a server must bind to 0.0.0.0 and you must open the listening port (usually process.env.PORT) in the Workspace or Deployment configuration. If you only listen on localhost or forget to expose the port, Sunshine can’t reach your endpoint.
import express from "express"
const app = express()
app.use(express.json())
app.post("/webhook", (req, res) => {
console.log(req.body)
res.sendStatus(200)
})
app.listen(process.env.PORT || 3000, "0.0.0.0") // Needed for Replit
Directly embedding your Sunshine Conversations appId or API key inside code makes it publicly visible to anyone viewing your Repl. Replit’s public Repls expose source files by default. Store credentials using Secrets (on the left panel → Secrets) and access them from process.env in Node.js. This prevents leaking sensitive tokens if you fork or share the Repl.
import fetch from "node-fetch"
const { SMOOCH_APP_ID, SMOOCH_KEY_ID, SMOOCH_SECRET } = process.env
// Properly using environment variables
fetch(`https://api.smooch.io/v2/apps/${SMOOCH_APP_ID}/messages`, {
headers: {
"Content-Type": "application/json",
Authorization: `Basic ${Buffer.from(`${SMOOCH_KEY_ID}:${SMOOCH_SECRET}`).toString("base64")}`
}
})
Developers often skip verifying Sunshine Conversations’ webhook signatures, assuming internal Replit traffic is private. It isn’t — every Repl has a public URL. To trust incoming requests, validate headers X-Smooch-Signature using your Secret Key. Without this, anyone can spoof events to your app. Node’s crypto module works well to compare signatures securely.
import crypto from "crypto"
function verifySmoochSignature(rawBody, signature, secret) {
const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex")
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
}
Replit free Repls sleep when idle; even Deployments restart on new pushes. If your Sunshine Conversations integration stores conversation IDs or auth tokens in memory or local files only, they vanish after restart. You must persist important state externally — for example, in Replit Database, or ideally an external database like Postgres or Redis.
// Simple use of Replit DB for message mapping
import Database from "@replit/database"
const db = new Database()
await db.set("conversation:12345", { lastMessageId: "abc" })
const conv = await db.get("conversation:12345")
console.log(conv)
This prompt helps an AI assistant understand your setup and guide you through the fix step by step, without assuming technical knowledge.
From startups to enterprises and everything in between, see for yourself our incredible impact.
Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We’ll discuss your project and provide a custom quote at no cost.Â