/how-to-build-replit

How to Build a Integration hub with Replit

Learn how to build an integration hub using Replit. Follow step-by-step instructions to connect apps, automate workflows, and boost productivity.

Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

How to Build a Integration hub with Replit

To build an Integration Hub on Replit, you’ll create a Node.js backend (using Express) that connects to external APIs, stores user configurations (via a small database or file), and provides routes for sending/receiving data. This backend acts as the “hub” — handling API calls on behalf of your integrations. In Replit, you can easily manage environment variables through the “Secrets” tab, test endpoints with the built-in webview, and even collaborate live. Below is a practical, real-world setup that actually runs inside Replit and can scale from a basic proof-of-concept to a real small integration hub.

 

Step 1: Create a Replit Node.js project

 

Start from the Replit template called “Node.js”. It automatically gives you an index.js entry file and adds Node dependencies management. This file is what launches when you click “Run.”

// In the Replit shell, if not already added, install Express
npm install express axios

 

Step 2: Set up your server

 

Open index.js (it’s in the root folder). Replace its contents with this code. This will be our integration hub’s core — handling basic routing, connection testing, and forwarding data.

// index.js

import express from "express"
import axios from "axios"

const app = express()
app.use(express.json())

// Basic check endpoint
app.get("/", (req, res) => {
  res.send("Integration Hub is running! 🚀")
})

// Example integration endpoint
app.post("/send-to-slack", async (req, res) => {
  try {
    // Access your Slack webhook URL from Replit Secrets
    const slackWebhook = process.env.SLACK_WEBHOOK_URL
    
    // message payload received from client
    const { message } = req.body 
    
    // Send to Slack
    await axios.post(slackWebhook, { text: message })
    
    res.status(200).json({ success: true, sent: message })
  } catch (error) {
    console.error(error)
    res.status(500).json({ success: false, message: "Failed to send message" })
  }
})

// Replit provides PORT automatically, default to 3000 if not set
const port = process.env.PORT || 3000
app.listen(port, () => console.log(`Server running on port ${port}`))

What this does: It creates a small Express server that listens for requests. The /send-to-slack endpoint takes a message and pushes it to Slack using a webhook URL stored securely in Replit Secrets.

 

Step 3: Use Replit Secrets for credentials

 

In the left sidebar, click the 🔒 “Secrets” icon. Add new secrets like:

  • Key: SLACK_WEBHOOK_URL
  • Value: your actual Slack webhook URL

This ensures sensitive data doesn’t live inside your code. In Replit, the environment variable will be available as process.env.SLACK_WEBHOOK_URL.

 

Step 4: Add additional integrations

 

Create a folder named integrations in the root of your project. Inside, you can create small service files for each external system (for example Slack, Notion, or Gmail). These files should only handle one responsibility — communicating with that external API.

Create a new file: integrations/slack.js

// integrations/slack.js
import axios from "axios"

export async function sendSlackMessage(text) {
  const webhookUrl = process.env.SLACK_WEBHOOK_URL
  const response = await axios.post(webhookUrl, { text })
  return response.data
}

Then update index.js to use it:

// index.js (replace the /send-to-slack endpoint)
import express from "express"
import { sendSlackMessage } from "./integrations/slack.js"

const app = express()
app.use(express.json())

app.post("/send-to-slack", async (req, res) => {
  try {
    const { message } = req.body
    const result = await sendSlackMessage(message)
    res.json({ success: true, result })
  } catch (err) {
    res.status(500).json({ success: false, error: err.message })
  }
})

 

Step 5: Test your integration hub

 

Click “Run” in Replit. The small window on the right should now display “Integration Hub is running!” Copy the public URL above that preview window.

You can test sending a message to Slack by using Replit’s shell:

curl -X POST https://your-repl-username.repl.co/send-to-slack \
-H "Content-Type: application/json" \
-d '{"message":"Hello from Replit Integration Hub!"}'

If everything is wired correctly, your Slack channel will receive the message.

 

Step 6: Add a persistent store (optional)

 

If you need to track integration logs or store config, Replit supports SQLite out-of-the-box.

npm install better-sqlite3

Create db.js file:

// db.js
import Database from "better-sqlite3"
const db = new Database("hub.db")

// Create a simple table (runs only once)
db.prepare("CREATE TABLE IF NOT EXISTS logs (id INTEGER PRIMARY KEY, event TEXT, date TEXT)").run()

export function saveLog(event) {
  db.prepare("INSERT INTO logs (event, date) VALUES (?, ?)").run(event, new Date().toISOString())
}

Then call saveLog() inside your integration routes to record each action.

 

Step 7: Make it collaborative and live

 

Replit allows live multiplayer editing by default. You can invite teammates using the “Invite” button. Each team member will see real-time updates and can even use the “Chat” pane for collaboration. For deployment, your Repl runs automatically on a public URL as long as it’s active; for persistent uptime, use Replit’s “Always On” if available in your plan.

 

Final notes

 

  • Replit’s runtime restarts after idle unless “Always On” is enabled — so use databases instead of in-memory objects to preserve data.
  • Use Replit Secrets for any API keys. Never hardcode them.
  • Use the built-in Console tab for live debugging (you can see console.log output immediately).
  • Keep integrations modular — one file per service to avoid clutter.

By following this setup exactly as shown, you’ll have a real, working Integration Hub running on Replit — capable of connecting multiple external APIs, managing credentials securely, and handling real requests like a production-grade small service.

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Contact Us

How to Build a Simple API Integration Hub with Express and Replit



import express from "express"
import bodyParser from "body-parser"
import axios from "axios"

const app = express()
app.use(bodyParser.json())

// Example integration registry
// In a real case these baseUrls or tokens would be in Replit Secrets
const integrations = {
  github: { baseUrl: "https://api.github.com", token: process.env.GH\_TOKEN },
  slack: { baseUrl: "https://slack.com/api", token: process.env.SLACK\_TOKEN },
}

// Simple routing layer for your integration hub
app.post("/integrate/:service/:action", async (req, res) => {
  const { service, action } = req.params
  const { payload } = req.body
  const integration = integrations[service]
  if (!integration) return res.status(400).json({ error: "Unknown service" })

  try {
    const headers = { Authorization: `Bearer ${integration.token}` }
    const endpoint = getEndpoint(service, action)
    const response = await axios.post(`${integration.baseUrl}${endpoint}`, payload, { headers })
    res.json({ data: response.data })
  } catch (err) {
    res.status(500).json({ error: err.message })
  }
})

// Example endpoint builder
function getEndpoint(service, action) {
  const map = {
    github: {
      createIssue: "/repos/:owner/:repo/issues",
    },
    slack: {
      sendMessage: "/chat.postMessage",
    },
  }
  return map[service]?.[action] || ""
}

app.listen(3000, () => console.log("Integration hub running on port 3000"))

How to Build a Secure Webhook Proxy for Your Integration Hub



import express from "express"
import crypto from "crypto"

const app = express()
app.use(express.json())

// Endpoint to receive webhook events & proxy them to connected integrations
app.post("/webhook/:source", async (req, res) => {
  const { source } = req.params
  const secret = process.env[`SECRET_${source.toUpperCase()}`]
  const signature = req.headers["x-signature"]
  const payload = JSON.stringify(req.body)

  if (!verifySignature(payload, signature, secret)) {
    return res.status(403).json({ error: "Invalid signature" })
  }

  // Example: fan out webhook event to multiple integrations
  const event = { source, data: req.body }
  try {
    await notifyIntegrations(event)
    res.status(200).json({ received: true })
  } catch (err) {
    res.status(500).json({ error: err.message })
  }
})

function verifySignature(payload, signature, secret) {
  const hmac = crypto.createHmac("sha256", secret).update(payload).digest("hex")
  return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(hmac))
}

async function notifyIntegrations(event) {
  // In a real app: store and fetch subscriber URLs from DB
  const subscribers = JSON.parse(process.env.INTEGRATION\_TARGETS || "[]")
  const fetch = (await import("node-fetch")).default
  await Promise.all(
    subscribers.map(url =>
      fetch(url, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(event),
      })
    )
  )
}

app.listen(3000, () => console.log("Webhook proxy live on port 3000"))

How to Build a Secure Multi‑Provider OAuth Bridge on Replit



import express from "express"
import axios from "axios"
import crypto from "crypto"

const app = express()
app.use(express.json())

// OAuth redirect handler for multiple external APIs using shared redirect URI in Replit
app.get("/oauth/callback/:provider", async (req, res) => {
  const { provider } = req.params
  const { code, state } = req.query
  const config = getProviderConfig(provider)
  if (!config) return res.status(400).json({ error: "Unknown provider" })

  try {
    // Exchange code for token
    const tokenResponse = await axios.post(config.tokenUrl, {
      client\_id: process.env[`${provider.toUpperCase()}_CLIENT_ID`],
      client\_secret: process.env[`${provider.toUpperCase()}_CLIENT_SECRET`],
      redirect\_uri: config.redirectUri,
      code,
      grant_type: "authorization_code",
    })
    const accessToken = tokenResponse.data.access\_token

    // Store encrypted token in memory or DB (example: temporary memory)
    const encrypted = encryptToken(accessToken, process.env.SECRET\_KEY)
    tokenStore[provider] = encrypted

    res.redirect(`/connected?provider=${provider}`)
  } catch (err) {
    res.status(500).json({ error: "Failed to complete auth", detail: err.message })
  }
})

// Example secured request proxy
app.post("/api/:provider/:endpoint", async (req, res) => {
  const { provider, endpoint } = req.params
  const tokenEncrypted = tokenStore[provider]
  if (!tokenEncrypted) return res.status(403).json({ error: "Not connected" })

  const token = decryptToken(tokenEncrypted, process.env.SECRET\_KEY)
  try {
    const response = await axios.post(
      `${getProviderConfig(provider).apiBase}/${endpoint}`,
      req.body,
      { headers: { Authorization: `Bearer ${token}` } }
    )
    res.json(response.data)
  } catch (err) {
    res.status(500).json({ error: "API call failed", detail: err.message })
  }
})

function getProviderConfig(provider) {
  const base = process.env.REPLIT\_URL || "http://localhost:3000"
  return {
    github: {
      tokenUrl: "https://github.com/login/oauth/access\_token",
      apiBase: "https://api.github.com",
      redirectUri: `${base}/oauth/callback/github`,
    },
    notion: {
      tokenUrl: "https://api.notion.com/v1/oauth/token",
      apiBase: "https://api.notion.com/v1",
      redirectUri: `${base}/oauth/callback/notion`,
    },
  }[provider]
}

const tokenStore = {}

function encryptToken(token, key) {
  const iv = crypto.randomBytes(16)
  const cipher = crypto.createCipheriv("aes-256-gcm", Buffer.from(key, "hex"), iv)
  const encrypted = Buffer.concat([cipher.update(token), cipher.final()])
  const tag = cipher.getAuthTag()
  return `${iv.toString("hex")}:${tag.toString("hex")}:${encrypted.toString("hex")}`
}

function decryptToken(data, key) {
  const [ivHex, tagHex, encHex] = data.split(":")
  const iv = Buffer.from(ivHex, "hex")
  const tag = Buffer.from(tagHex, "hex")
  const enc = Buffer.from(encHex, "hex")
  const decipher = crypto.createDecipheriv("aes-256-gcm", Buffer.from(key, "hex"), iv)
  decipher.setAuthTag(tag)
  const decrypted = Buffer.concat([decipher.update(enc), decipher.final()])
  return decrypted.toString()
}

app.listen(3000, () => console.log("Integration auth bridge running on port 3000"))

Want to explore opportunities to work with us?

Connect with our team to unlock the full potential of no-code solutions with a no-commitment consultation!

Contact Us
Matt Graham, CEO of Rapid Developers

Book a call with an Expert

Starting a new venture? Need to upgrade your web app? RapidDev builds application with your growth in mind.

Best Practices for Building a Integration hub with Replit

When building an Integration Hub on Replit — meaning a central web app that connects to multiple third-party services (like Slack, Google, or custom APIs) — the best practice is to structure your project cleanly, isolate secrets, and handle network calls with async-safe code. You should use a simple Express.js (Node.js) backend combined with a lightweight frontend (HTML or React if needed). Replit can easily host this as a public web server, but you must be careful with API keys, persistent storage, and rate limits. The goal is to create clean separation: frontend for user interface, backend for integrating with external APIs, and environment variables for credentials.

 

Folder and File Structure

 

Inside your Replit project (a “Repl”), keep a clear structure like:

  • index.js — main server entry (Express configuration)
  • routes/ — folder for separate integration routes (e.g. routes/slack.js, routes/google.js)
  • services/ — optional folder to hold reusable API helper functions
  • public/ — static files if you’re serving a frontend here

 

Setting up the Server

 

In Replit, create a file named index.js. This file will start your web server and load environment variables safely. Use Replit’s built-in “Secrets” tab (lock icon in sidebar) to define credentials like GOOGLE_API_KEY or SLACK_TOKEN. These will be available inside your Node app as process.env.MY_SECRET\_NAME.

 

// index.js
import express from "express" // express framework for routing
import cors from "cors"
import dotenv from "dotenv"

dotenv.config() // loads .env fallback in local environments

const app = express()
app.use(express.json()) // parse incoming JSON
app.use(cors()) // needed when you'll call from another domain or Replit frontend

app.get("/", (req, res) => {
  res.send("Integration Hub is running!")
})

// Import integration routes
import slackRouter from "./routes/slack.js"
import googleRouter from "./routes/google.js"

app.use("/slack", slackRouter)
app.use("/google", googleRouter)

// Replit exposes process.env.PORT for your web server
const port = process.env.PORT || 3000
app.listen(port, () => console.log(`Server running on port ${port}`))

 

Creating Integration Routes

 

Inside a new folder called routes/, create a file named slack.js. This handles all requests related to the Slack integration. The same pattern can be used for any API (Google, Notion, etc.) — each gets its own route file.

 

// routes/slack.js
import express from "express"
import fetch from "node-fetch" // built-in in newer Node versions, else install with npm
const router = express.Router()

router.post("/send-message", async (req, res) => {
  // this endpoint expects a 'text' field in the request body
  const { text } = req.body

  if (!process.env.SLACK_TOKEN) {
    return res.status(500).send("Missing Slack token in Secrets")
  }

  const response = await fetch("https://slack.com/api/chat.postMessage", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "Authorization": `Bearer ${process.env.SLACK_TOKEN}`,
    },
    body: JSON.stringify({
      channel: "#general", // your Slack channel
      text: text || "Hello from Replit Integration Hub!",
    }),
  })

  const data = await response.json()
  res.json(data)
})

export default router

 

Place similar route files (like google.js) inside the same folder for other APIs. Keep each one focused: fetch external data, parse it, and return clean JSON responses. This modular approach makes debugging easier and prevents messy logic in a single file.

 

Managing Secrets and Environment Variables

 

On Replit, click the lock icon (Secrets tab) in the left sidebar and add your keys one by one:

  • Key: SLACK\_TOKEN, Value: your Slack Bot User OAuth Token
  • Key: GOOGLE_API_KEY, Value: Google project key

Never hardcode values directly in your code. They’re visible publicly if the Repl is shared. Using Secrets prevents leaks and works identically in the deployed web URL.

 

Frontend (Optional)

 

If you want a small frontend dashboard, create an index.html file inside public/ and add this snippet in your Express config to serve it:

 

// Add inside index.js before routes
app.use(express.static("public"))

 

This makes Replit serve your HTML interface from https://your-repl-name.username.repl.co. That page can perform fetch() calls to your backend routes (like /slack/send-message).

 

Database and State

 

If your Integration Hub needs to save user preferences or logs, use Replit’s built-in Replit Database or connect an external one (like MongoDB Atlas). For small-scale projects, this is enough:

 

// services/db.js
import Database from "@replit/database"
const db = new Database()

// Example usage
export const saveMessage = async (key, value) => {
  await db.set(key, value)
}

export const getMessage = async (key) => {
  return await db.get(key)
}

 

Then import it into your routes to store or retrieve integration data safely:

 

import { saveMessage } from "../services/db.js"

// After successful Slack message send
await saveMessage("lastMessage", text)

 

Testing and Deployment

 

You don’t need to “deploy” manually — once your Repl runs, it hosts your server automatically on a public URL. If you’re testing webhooks (for example, Slack outgoing webhooks or OAuth callbacks), copy the Replit URL shown by the “Open in new tab” button and use it directly as the callback URL in your external service configuration.

A common pitfall is the Replit sleep mode: Always-On Repls (paid feature) are necessary if you need your hub online 24/7; otherwise, the Repl stops when idle. For testing or development, the free plan works fine.

 

Final Tips

 

  • Keep each integration isolated. Never mix logic for different services in one route file.
  • Always validate incoming requests. Don’t trust that third-party webhooks are genuine unless you verify them (e.g., Slack signing secret).
  • Limit dependencies. Replit has finite storage and sometimes network limits — keep packages lightweight.
  • Use console.log generously. Replit’s Console shows your logs in real time. Use it to debug integration calls.
  • Shrink payloads. If API responses are large, only store or send the fields you need to the frontend.

 

Following these patterns gives you a stable Integration Hub hosted on Replit — modular, secure with Secrets, and easy to expand by adding new route files for more services as your app grows.

Client trust and success are our top priorities

When it comes to serving you, we sweat the little things. That’s why our work makes a big impact.

Rapid Dev was an exceptional project management organization and the best development collaborators I've had the pleasure of working with. They do complex work on extremely fast timelines and effectively manage the testing and pre-launch process to deliver the best possible product. I'm extremely impressed with their execution ability.

CPO, Praction - Arkady Sokolov

May 2, 2023

Working with Matt was comparable to having another co-founder on the team, but without the commitment or cost. He has a strategic mindset and willing to change the scope of the project in real time based on the needs of the client. A true strategic thought partner!

Co-Founder, Arc - Donald Muir

Dec 27, 2022

Rapid Dev are 10/10, excellent communicators - the best I've ever encountered in the tech dev space. They always go the extra mile, they genuinely care, they respond quickly, they're flexible, adaptable and their enthusiasm is amazing.

Co-CEO, Grantify - Mat Westergreen-Thorne

Oct 15, 2022

Rapid Dev is an excellent developer for no-code and low-code solutions.
We’ve had great success since launching the platform in November 2023. In a few months, we’ve gained over 1,000 new active users. We’ve also secured several dozen bookings on the platform and seen about 70% new user month-over-month growth since the launch.

Co-Founder, Church Real Estate Marketplace - Emmanuel Brown

May 1, 2024 

Matt’s dedication to executing our vision and his commitment to the project deadline were impressive. 
This was such a specific project, and Matt really delivered. We worked with a really fast turnaround, and he always delivered. The site was a perfect prop for us!

Production Manager, Media Production Company - Samantha Fekete

Sep 23, 2022