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 integrates with HubSpot the same way it would from any other runtime: using HubSpot’s public APIs (REST or GraphQL) over HTTPS, authenticated with either a Private App Access Token or an OAuth 2.0 flow. In a Repl, you store credentials in Replit Secrets, call HubSpot APIs through fetch or a server library (like Express + axios or node-fetch), and optionally handle inbound webhooks from HubSpot by exposing a public URL via Replit’s web server port. There’s no “Replit-specific” HubSpot integration — everything is explicit and uses HubSpot’s documented endpoints and authentication methods.
You’re basically building a small backend app inside Replit that talks to HubSpot via HTTPS. Replit runs your code (like a Node.js or Python app), you store tokens as environment variables, and your app uses them to call HubSpot API endpoints such as creating contacts, updating deals, or listening to CRM webhooks. Since Replit provides a public URL for running Repls, you can also receive callbacks or webhooks from HubSpot in real time.
This example shows creating a contact in HubSpot CRM from a Node.js Replit app using a Private App Access Token.
// index.js
import express from "express"
import fetch from "node-fetch"
const app = express()
app.use(express.json())
// Replit Secret should store your HubSpot private app access token
const HUBSPOT_TOKEN = process.env.HUBSPOT_TOKEN
app.post("/create-contact", async (req, res) => {
try {
const response = await fetch("https://api.hubapi.com/crm/v3/objects/contacts", {
method: "POST",
headers: {
"Authorization": `Bearer ${HUBSPOT_TOKEN}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
properties: {
email: req.body.email,
firstname: req.body.firstname,
lastname: req.body.lastname
}
})
})
const data = await response.json()
res.json(data)
} catch (error) {
console.error(error)
res.status(500).json({ error: "Error creating contact" })
}
})
// Replit server binds to 0.0.0.0 and exposes via its public URL
app.listen(3000, "0.0.0.0", () => {
console.log("Server running on port 3000")
})
https://your-repl-name.username.repl.co./create-contact endpoint with a JSON body containing email, firstname, and lastname.
curl -X POST https://your-repl-name.username.repl.co/create-contact \
-H "Content-Type: application/json" \
-d '{"email":"[email protected]","firstname":"Jane","lastname":"Doe"}'
If you want HubSpot to send you data automatically (like when contacts are updated), you create an endpoint in your Replit web server and register it in HubSpot under “Developer Account → Webhooks”. HubSpot will POST JSON payloads to your public Replit URL, which you verify using the provided signature headers.
app.post("/hubspot-webhook", (req, res) => {
console.log("Webhook received from HubSpot:", req.body)
res.sendStatus(200) // Always respond quickly to acknowledge
})
With this setup, you’ve built a real, functioning HubSpot integration running entirely in Replit’s environment — secure, simple, and based on the official APIs.
1
Connect HubSpot’s Contact API to a Replit-hosted backend (for example, a Node.js app). This lets your Replit app automatically fetch and store HubSpot contact data in your own database or in-memory cache. It’s useful when your app needs HubSpot customer info to personalize a user dashboard or trigger actions based on CRM activity. Use Replit Secrets to store the HubSpot API key or OAuth token, and run your sync as a Replit Workflow so it executes periodically or on-demand. This integration follows explicit REST calls and uses environment variables for secure credentials handling.
your_private_keyserver.listen(8080, "0.0.0.0") to expose your app./crm/v3/objects/contacts endpoint via HTTPS.import express from "express"
import fetch from "node-fetch"
const app = express()
app.get("/sync", async (req, res) => {
const r = await fetch("https://api.hubapi.com/crm/v3/objects/contacts", {
headers: { Authorization: `Bearer ${process.env.HUBSPOT_API_KEY}` }
})
const data = await r.json()
res.json(data)
})
app.listen(8080, "0.0.0.0", () => console.log("Server running"))
2
HubSpot can send real-time updates (webhooks) when contacts, deals, or tickets change. You can receive those webhook POST requests directly in a Replit-hosted Express app. This is reliable for integrating lead updates into other systems or triggering follow-up actions. Keep in mind that Replit restarts occasionally, so keep logic stateless or forward the data to an external store. Use Replit’s live view and console to debug webhook requests while HubSpot sends test events.
req.body and store or forward it.import express from "express"
const app = express()
app.use(express.json())
app.post("/hubspot/webhook", (req, res) => {
console.log("Received HubSpot event:", req.body)
res.sendStatus(200)
})
app.listen(8080, "0.0.0.0", () => console.log("Listening for HubSpot webhooks"))
3
Create a lightweight automation app that uses HubSpot’s Engagements or CRM APIs to detect new leads and sends follow-up emails or Slack notifications automatically. This app can run as a Replit Workflow triggered hourly or manually. It retrieves new leads via REST, checks certain conditions (for example new deal stage), then triggers HubSpot’s email API or integrates another outbound channel. Keeping it inside Replit lets you prototype business automation with real API events before moving to a production platform.
node app.js./crm/v3/objects/deals for deal info, and /marketing/v3/transactional-emails/single-send for outbound.import fetch from "node-fetch"
async function run() {
const deals = await fetch("https://api.hubapi.com/crm/v3/objects/deals", {
headers: { Authorization: `Bearer ${process.env.HUBSPOT_API_KEY}` }
}).then(r => r.json())
for (const d of deals.results) {
if (d.properties.dealstage === "new") {
await fetch("https://api.hubapi.com/marketing/v3/transactional-emails/single-send", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.HUBSPOT_API_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({ emailId: "12345", message: { to: "[email protected]" } })
})
}
}
}
run()
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 HubSpot API key isn’t being recognized in Replit Secrets because it’s either not properly set as an environment variable or the Repl environment hasn’t been restarted after adding it. Replit Secrets are injected into your runtime as environment variables, and your code must read them exactly by key name — case-sensitive — using process.env in Node.js.
echo $HUBSPOT_API_KEY
// Access HubSpot API key stored in Replit Secrets
const hubspotKey = process.env.HUBSPOT_API_KEY;
if (!hubspotKey) {
console.error("HubSpot API key not found. Check Replit Secrets and restart your Repl.");
}
Once the key resolves correctly, HubSpot calls (e.g., via axios or official SDK) will authenticate normally. Misnaming the key or expecting automatic import breaks auth immediately.
2
CORS errors happen because browsers block frontend JavaScript from calling external domains like HubSpot directly. To fix this in Replit, never call the HubSpot API from client-side code. Instead, build a small backend proxy in your Repl (Node.js or Python) that runs server-side and makes the HubSpot API request using your secret key or OAuth token. The browser talks only to your Replit server (same origin), eliminating the CORS issue.
// server.js
import express from "express"
import fetch from "node-fetch"
const app = express()
app.use(express.json())
app.get("/api/contacts", async (req, res) => {
const response = await fetch("https://api.hubapi.com/crm/v3/objects/contacts", {
headers: { Authorization: `Bearer ${process.env.HUBSPOT_TOKEN}` }
})
const data = await response.json()
res.json(data)
})
app.listen(3000, "0.0.0.0", () => console.log("Server running"))
This proxy pattern works reliably in Replit Workflows or Deployments, avoids CORS entirely, and keeps tokens secret on the server.
3
A 401 error from HubSpot when using fetch inside a Replit Repl almost always means the authorization header (your HubSpot API key or access token) is missing, malformed, or expired. In Replit, this often happens if the secret isn’t read correctly from process.env, or if you’re trying to call the API directly from the browser instead of through the server side of your Repl, which exposes the token publicly and gets blocked.
Check that your token is saved in Replit Secrets (the lock icon on sidebar), then used server‑side only in your fetch call via process.env. HubSpot’s APIs require either a Private App token (“Bearer …”) or an OAuth access token. Always include the correct header and make sure the token has not expired.
// Example of a valid server-side call in Replit
import fetch from "node-fetch"
const HUBSPOT_TOKEN = process.env.HUBSPOT_PRIVATE_APP_TOKEN
const res = await fetch("https://api.hubapi.com/crm/v3/objects/contacts", {
headers: {
"Authorization": `Bearer ${HUBSPOT_TOKEN}`,
"Content-Type": "application/json"
}
})
const data = await res.json()
console.log(data)
Developers often forget that Replit Repls run behind a dynamic preview URL that changes when restarted. HubSpot webhooks need a fixed, publicly reachable HTTPS endpoint to send events to. If you don’t use the correct exposed URL or deploy with an explicit mapped port, HubSpot can’t verify or reach your webhook.
import express from "express"
const app = express()
app.post("/webhook", (req, res) => { res.sendStatus(200) })
app.listen(3000, "0.0.0.0") // Bind for Replit public access
Copying your HubSpot Private App token directly into the source leads to leakage the moment someone forks or views the Repl. Replit offers Secrets for this reason — they store tokens as environment variables only available at runtime. Always read sensitive values with process.env instead of hardcoding.
const HUBSPOT_TOKEN = process.env.HUBSPOT_TOKEN
const headers = { Authorization: `Bearer ${HUBSPOT_TOKEN}` }
HubSpot OAuth apps require a fixed redirect URI. Replit’s running Repls generate a new URL each session, breaking OAuth callbacks. HubSpot will reject authorization if the redirect URL doesn’t match exactly. To integrate properly, deploy your Repl or use a Replit Deployment URL which stays stable.
// Redirect URL must match exactly what you registered in HubSpot
const REDIRECT_URI = process.env.REDIRECT_URI
app.get("/auth/hubspot/callback", async (req, res) => { /* handle tokens */ })
Replit processes can restart anytime, and HubSpot applies API rate limits. Without caching or persistence outside Replit, integrations can lose sync state or repeatedly fail. If you rely only on in-memory variables, they reset when the Repl sleeps or rebuilds. Always plan for idempotent requests and store data in HubSpot or an external database.
if (response.status === 429) {
const retryAfter = response.headers["retry-after"]
await new Promise(r => setTimeout(r, retryAfter * 1000))
}
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.Â