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.
To integrate Replit with Acuity Scheduling, the practical and reliable method is to run a small web server inside your Repl, expose it on a public URL using Replit’s built‑in port mapping, then configure Acuity Scheduling to send webhooks to that URL. You then use Acuity’s official REST API (no SDK exists) by calling it directly with HTTPS requests. You store your Acuity API credentials using Replit Secrets, never in code. Once this setup is running, you can automate appointment actions, send notifications, update databases, or trigger other third‑party systems, all from inside your Repl.
You run a tiny backend inside Replit that Acuity can talk to. Acuity sends you data (via webhooks), and when you need to talk to Acuity, you call their REST API over HTTPS. Everything is done explicitly. You must expose a public URL and keep your Acuity API credentials safe using Replit Secrets.
This is the reliable pattern used for real production-style integrations on Replit. Simple, explicit, and works with Acuity's actual API.
Acuity uses Basic Auth with an API User ID and API Key. Both come from your Acuity account under the “API” or “Integrations” section.
In your Repl, open the left panel → Secrets → add:
This makes them available as environment variables while your server is running.
Below is a minimal Flask server (Python) that you can extend. You can use Node.js or another framework too—Replit supports all of them. The only rule: bind to 0.0.0.0 so Replit exposes your port.
# main.py
import os
import base64
import requests
from flask import Flask, request, jsonify
app = Flask(__name__)
ACUITY_USER_ID = os.environ["ACUITY_USER_ID"]
ACUITY_API_KEY = os.environ["ACUITY_API_KEY"]
# Build Acuity Basic Auth header
auth_str = f"{ACUITY_USER_ID}:{ACUITY_API_KEY}"
AUTH_HEADER = {
"Authorization": "Basic " + base64.b64encode(auth_str.encode()).decode()
}
@app.route("/webhook", methods=["POST"])
def webhook():
// Acuity will POST appointment events here
data = request.json
// Log to console while developing
print("Received Acuity webhook:", data)
// You can respond with anything, Acuity requires 200 OK
return jsonify({"status": "received"})
@app.route("/api/appointments")
def list_appointments():
// Example call to Acuity's official API
r = requests.get(
"https://acuityscheduling.com/api/v1/appointments",
headers=AUTH_HEADER
)
return jsonify(r.json())
if __name__ == "__main__":
// Must bind to 0.0.0.0; Replit maps this to a public HTTPS URL
app.run(host="0.0.0.0", port=8000)
When you click "Run," Replit detects that your server is listening on port 8000 and gives you a public HTTPS URL like:
https://your-repl-name.username.repl.co
Your webhook endpoint will be:
https://your-repl-name.username.repl.co/webhook
This must be reachable from the internet for Acuity to send data.
Inside your Acuity account, you can configure webhooks under the “API” or “Integrations” area. You will paste the public URL you got from Replit.
Acuity will POST JSON to your Repl whenever events happen.
Acuity’s webhook system does not provide a signature verification mechanism, so if you need verification, use a shared secret in the URL or add your own token check in the handler.
Acuity’s API is simple. You use their REST endpoints with your Basic Auth header. The earlier code example already showed a working request for listing appointments. The same pattern works for modifying appointments, creating blocks, fetching availability, etc.
Replit Workflows can run scheduled tasks (cron-like) that call your Python script or hit your internal API endpoint.
This offloads periodic work from your long-running server.
Integrating Replit with Acuity Scheduling is straightforward: run a small server in Replit, expose a webhook endpoint, securely store your API credentials using Replit Secrets, and use Acuity’s official REST API for outbound requests. This pattern is reliable, production-safe (for light workloads), and fits perfectly with Replit’s explicit full-stack model.
1
Use Replit to run a small backend server that receives Acuity Scheduling webhooks every time an appointment is created, rescheduled, or canceled. The server runs in a Repl, listens on 0.0.0.0, and exposes a public URL through Replit’s port mapping so Acuity can reach it. This lets you trigger custom actions (emails, database writes, Slack messages) without needing your own infrastructure.
// Basic Express webhook listener in Replit
import express from "express";
import crypto from "crypto";
const app = express();
app.use(express.json());
app.post("/acuity-webhook", (req, res) => {
// Verify signature if enabled
const signature = req.headers["x-acuity-signature"];
const expected = crypto.createHmac("sha256", process.env.ACUITY_SECRET)
.update(JSON.stringify(req.body))
.digest("hex");
if (signature !== expected) return res.status(401).send("Invalid signature");
console.log("New appointment event:", req.body);
res.send("ok");
});
app.listen(3000, "0.0.0.0", () => console.log("Webhook listener running"));
2
Build a lightweight frontend + backend in a single Repl that fetches Acuity Scheduling REST API data and displays it in a dashboard. The backend talks to Acuity using API credentials from Replit Secrets, and the frontend fetches from your own API routes. This avoids exposing Acuity credentials to the browser and keeps all logic server-side.
// Server route returning today's appointments
import express from "express";
import fetch from "node-fetch";
const app = express();
app.get("/api/appointments", async (req, res) => {
const auth = `${process.env.ACUITY_USER}:${process.env.ACUITY_API_KEY}`;
const resp = await fetch("https://acuityscheduling.com/api/v1/appointments", {
headers: { Authorization: "Basic " + Buffer.from(auth).toString("base64") }
});
const data = await resp.json();
res.json(data);
});
app.listen(3000, "0.0.0.0");
3
Use Replit Workflows to run a scheduled job (e.g., nightly) that pulls appointment data from Acuity and syncs it into an external database such as Supabase, PostgreSQL, or Google Sheets API. Workflows allow the sync script to run even when the Repl isn’t open, making the whole integration automated and maintenance‑light.
# Example workflow in replit.nix-style YAML (run script nightly)
on:
schedule:
- cron: "0 3 * * *" # 3 AM UTC
run:
command: ["node", "sync.js"]
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 request fails because Acuity requires HTTP Basic Auth with your API User ID and Key, but your Replit fetch runs without proper headers or tries sending them through frontend code. Browsers block those credentials, and Replit won’t expose secrets to client-side JS. So Acuity sees the call as unauthenticated and rejects it.
Acuity’s API only accepts server‑side requests using Basic Auth. On Replit, secrets live in environment variables, so the call must happen in a backend file (Node, Python, etc.). Frontend calls leak nothing because Replit strips secrets. That’s why the API request silently fails.
// server.js
import fetch from "node-fetch";
const user = process.env.ACUITY_USER;
const key = process.env.ACUITY_KEY;
const auth = Buffer.from(`${user}:${key}`).toString("base64");
const res = await fetch("https://acuityscheduling.com/api/v1/appointments", {
headers: { Authorization: `Basic ${auth}` }
});
2
If Acuity API variables aren't loading, ensure they are created in Replit Secrets, named exactly as used in your code, and that the Repl is restarted after saving. In Replit, secrets only become environment variables for running processes after a restart, and typos or saving them in the wrong section prevents loading.
The main issues are usually spelling mismatches, forgetting to press Add secret, or expecting secrets to auto‑reload. Re-open the Secrets panel, confirm each key exists, then stop and run the Repl again. Access them with process.env.MY_KEY in Node or os.getenv('MY_KEY') in Python.
import os
api_key = os.getenv("ACUITY_API_KEY") # Must match Secret name exactly
print(api_key)
3
Your Replit server isn’t receiving Acuity webhooks because the webhook URL you gave Acuity doesn’t point to a public, always‑running, externally reachable endpoint. A Repl only accepts incoming HTTP calls while it is actively running and exposing a mapped port, and Acuity requires a stable URL that doesn’t sleep or change.
Acuity sends webhooks to a fixed HTTPS address. A Repl’s preview URL changes on each restart, stops when the Repl sleeps, and only works if your server binds to 0.0.0.0 and the port is mapped. If any of these fail, Acuity’s webhook call gets a timeout.
import express from "express";
const app = express();
app.use(express.json());
app.post("/acuity", (req, res) => {
console.log(req.body); // Incoming webhook
res.sendStatus(200);
});
app.listen(process.env.PORT, "0.0.0.0"); // Required on Replit
Developers often paste Acuity credentials directly into code or confuse the User ID/API Key pair with OAuth keys. In Replit, you must store them in Secrets and read them as environment variables at runtime. Wrong or exposed credentials cause silent 401 errors and break Workflows that call Acuity’s REST endpoints.
// Example: loading Acuity creds from Replit Secrets
const ACUITY_USER_ID = process.env.ACUITY_USER_ID;
const ACUITY_API_KEY = process.env.ACUITY_API_KEY;
Acuity sends webhooks to a public URL, but many developers only run a local server on Replit without exposing a port. You must bind to 0.0.0.0 and let Replit assign the public URL. Without this, Acuity can’t reach your Repl, causing missed appointment events.
// Express server on Replit that Acuity can reach
app.listen(3000, '0.0.0.0', () => console.log('Server ready'));
Many assume Acuity webhook payloads are always safe. But without validating the X-Acuity-Signature header using your API key, your endpoint will accept spoofed or replayed requests. On Replit, you should verify signatures before processing events to avoid corrupting downstream workflows.
// Minimal HMAC check example
import crypto from 'crypto';
function validSignature(body, sig, key) {
const h = crypto.createHmac('sha256', key).update(body).digest('hex');
return h === sig;
}
Acuity integrations often rely on storing last-seen timestamps or event IDs. On Replit, in-memory state is lost when the process restarts. If you don’t persist data to a file or external DB, webhook logic may duplicate actions or miss updates after restarts or deployments.
// Simple JSON file persistence
import fs from 'fs';
fs.writeFileSync('state.json', JSON.stringify({ lastEvent: Date.now() }));
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.Â