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 Teachable, you don’t connect them directly (there’s no built-in Teachable SDK or native integration inside Replit). Instead, you use Teachable’s public API (or webhooks) and run your logic from a Replit-hosted backend – typically a small Express.js server or Python Flask app. That app can automate tasks such as enrolling users when they complete a form, verifying purchases, or syncing user data. Credentials (API keys, secret tokens) must be stored securely inside Replit Secrets. You expose your app by binding to 0.0.0.0 and accessing it through Replit’s generated URL, which can then be set as the webhook endpoint inside Teachable (for example, for enrollment events or purchase notifications).
// Install Express by running: npm install express axios
import express from "express"
import axios from "axios"
const app = express()
app.use(express.json())
// Teachable API key stored safely in Replit Secrets
const TEACHABLE_API_KEY = process.env.TEACHABLE_API_KEY
// Example endpoint: enroll a user in a Teachable course
app.post("/enroll-user", async (req, res) => {
const { email, course_id } = req.body
try {
const response = await axios.post(
`https://api.teachable.com/v1/courses/${course_id}/enrollments`,
{ user: { email: email } },
{
headers: {
"Accept": "application/json",
"Api-Key": TEACHABLE_API_KEY,
},
}
)
res.status(200).json({ message: "User enrolled successfully", data: response.data })
} catch (err) {
res.status(500).json({ error: err.message })
}
})
// Endpoint to receive webhooks from Teachable (example: "course.completed")
app.post("/webhook", (req, res) => {
console.log("Webhook received:", req.body)
// Always verify source if Teachable provides a signature header
res.status(200).send("ok")
})
// Start the Replit app
app.listen(3000, "0.0.0.0", () => {
console.log("Server running on port 3000")
})
https://yourreplname.username.repl.co/webhook.
Think of Replit as the “control room” and Teachable as the “school building.” You’ll use Replit to send instructions (through Teachable’s API) or listen to notifications (through Teachable’s webhooks). Replit hosts the small app that acts as the bridge between your systems. Every API key or access token must be stored in Replit’s Secrets so it’s safe. When someone buys a course or finishes a lesson in Teachable, your webhook on Replit can log it, send an email, or update another system depending on what you program it to do. That’s how real-world integrations are typically built — explicitly, via defined endpoints and authenticated API calls, not magic buttons.
1
When a student pays on Teachable, you can automatically add them to a coding sandbox hosted on Replit. You do this by listening to Teachable’s webhook events (like enrollment.created) and processing them inside a Replit-hosted server. The Replit app receives the webhook, verifies its signature, and then uses the Replit API to create a new Repl or provision workspace access. All credentials (Teachable API key, signing secret, Replit token) live inside Replit Secrets. You can expose your Repl’s server publicly via the mapped port to accept the webhook directly. This allows dynamic user onboarding without manual intervention.
from flask import Flask, request
import os, hmac, hashlib
app = Flask(__name__)
@app.route("/teachable-webhook", methods=["POST"])
def webhook():
secret = os.environ["TEACHABLE_SECRET"]
signature = request.headers.get("X-Teachable-Signature")
check = hmac.new(secret.encode(), request.data, hashlib.sha256).hexdigest()
if hmac.compare_digest(signature, check):
data = request.json
# create workspace or update record here
return "ok"
return "unauthorized", 403
app.run(host="0.0.0.0", port=8000)
2
You can connect both Teachable’s course data API and Replit’s API to display each student’s actual code progress and course progress together. The Replit side runs a Python or Node.js app pulling live stats via the Replit GraphQL endpoint (like runtime usage or project metadata). The Teachable side exposes the student’s lesson completion status through its REST API. Then your Replit web service combines and serves this as a dynamic dashboard. All API tokens are stored in Replit Secrets. This helps instructors monitor how students apply the lessons directly in coding environments.
import requests, os
TEACHABLE_API = "https://your-school.teachable.com/api/v1/users"
token = os.environ["TEACHABLE_API_KEY"]
res = requests.get(TEACHABLE_API, headers={"apiKey": token})
for user in res.json().get("users", []):
print(user["email"], user["progress_percent"])
3
Instead of offering only static lesson content in Teachable, you can integrate Replit embeds directly into course pages. Replit provides a ready-to-use <iframe> embed that runs live code inside the browser. Instructors create template Repls for each module, and then paste embed URLs into Teachable’s lesson editor. When students view a Teachable lesson, they can code instantly, execute programs, and save solutions back to their Replit account. This uses standard web embedding—no secret keys needed—but still respects Replit’s execution sandbox limits. It transforms Teachable courses into real coding labs accessible from any device.
<iframe height="400px" width="100%" src="https://replit.com/@yourusername/python-basics?embed=true" frameborder="0"></iframe>
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
Teachable API authentication errors on Replit usually happen because the API key or token isn’t correctly passed from Replit Secrets (environment variables) into your running code. To fix it, double-check that your Replit Secret key name matches exactly what your code expects, that you restart the Repl after setting secrets, and that your HTTP request includes this key properly in the Authorization header.
// Example in Node.js using fetch API
const fetch = require('node-fetch')
async function getCourses() {
const res = await fetch('https://developers.teachable.com/api/v1/courses', {
headers: {
'Authorization': `Bearer ${process.env.TEACHABLE_API_KEY}`
}
})
const data = await res.json()
console.log(data)
}
getCourses()
If the key still fails, print console.log(process.env.TEACHABLE_API_KEY) temporarily (without logging it publicly) to confirm it’s loaded. Each Replit restart resets environment, so always store long‑term credentials only via Secrets, never in code.
2
Replit isn’t loading Teachable webhook data in your Flask server because Teachable can’t reach your Repl’s internal address. Flask on Replit must bind to 0.0.0.0 and expose the exact port mapped by Replit (commonly 8000). The webhook URL sent to Teachable must be the public HTTPS URL of your running Repl — not “localhost” or the Replit editor preview link. Also, Replit spins down inactive Repls, so webhooks fail unless the server is actively running or deployed.
Start with explicit network binding and verify that your webhook uses the correct external URL and method (usually POST with JSON).
from flask import Flask, request
app = Flask(__name__)
@app.route("/webhook", methods=["POST"])
def teachable():
data = request.get_json() # Read webhook JSON body
print(data)
return "ok", 200
app.run(host="0.0.0.0", port=8000) # Required for Replit
If data still doesn’t arrive, check Replit console logs and ensure your Repl is running when Teachable sends events.
3
The Teachable JSON response times out on Replit because Teachable’s API can take longer than Replit’s default request timeout (usually 30 seconds). To handle this, don’t wait synchronously for Teachable’s JSON response inside a single HTTP call. Instead, trigger Teachable’s API in the background, store the request status, and let your frontend or webhook confirm completion asynchronously.
// Example: Express route avoiding long Teachable wait
import express from "express"
import fetch from "node-fetch"
const app = express()
app.post("/start-teachable-job", async (req, res) => {
res.json({ status: "processing" }) // respond fast
// run background task
fetch("https://teachablerequesturl", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.TEACHABLE_KEY}` }
}).then(r => r.json()).then(result => {
console.log("Teachable done", result)
})
})
app.listen(3000, "0.0.0.0")
Teachable can send webhooks (POST requests) to your Replit server when events happen, like a new enrollment. Many forget that Replit stops inactive Repls, so background servers won’t always receive those webhooks. Also, Teachable webhooks must be verified: always check the X-Teachable-Signature header using your shared secret to ensure the data really comes from Teachable.
// Example: webhook signature verification
import crypto from "crypto";
import express from "express";
const app = express();
app.use(express.json());
app.post("/webhook", (req, res) => {
const signature = req.headers["x-teachable-signature"];
const expected = crypto
.createHmac("sha256", process.env.TEACHABLE_WEBHOOK_SECRET)
.update(JSON.stringify(req.body))
.digest("hex");
if (signature !== expected) return res.status(403).send("Invalid signature");
res.send("ok");
});
app.listen(3000);
Developers often bind their Express or Flask server to localhost or port 5000 by habit. In Replit, external access must use host 0.0.0.0 and a mapped port (for example, from process.env.PORT). Otherwise, Teachable webhooks or OAuth redirects can’t reach the Repl.
// Correct Replit-style server binding
import express from "express";
const app = express();
app.get("/", (req, res) => res.send("Server OK"));
app.listen(process.env.PORT || 3000, "0.0.0.0");
Placing the Teachable API key directly inside your code file is unsafe — anyone who can see the Repl can see your credentials. The right way is using Replit Secrets. Secrets are environment variables stored securely and injected when your app runs.
// Load credentials from Replit Secrets
const fetch = (await import("node-fetch")).default;
const headers = {
Authorization: `Bearer ${process.env.TEACHABLE_API_KEY}`, // secret env var
};
const res = await fetch("https://developers.teachable.com/api/v1/courses", { headers });
const data = await res.json();
console.log(data);
Replit’s filesystem isn’t made for persistent or high-volume state (like user data or enrollments). When your Repl restarts or updates, this local data can disappear. Teachable already stores users and course info, so persist only what you must — and store it in a proper external DB (like Supabase or Firebase) if needed.
// Example: fetching enrollment instead of storing locally
import fetch from "node-fetch";
const res = await fetch(`https://developers.teachable.com/api/v1/enrollments`, {
headers: { Authorization: `Bearer ${process.env.TEACHABLE_API_KEY}` },
});
const enrollments = await res.json();
console.log(enrollments);
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.Â