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 Sage Pay (now called Opayo by Elavon), you treat Replit as a normal server environment: run an API or web server inside your Repl, expose a port, use HTTPS via Replit’s public URL, store Opayo credentials in Replit Secrets, and implement Opayo’s REST or Form Integration flow. Nothing is automatic. You must explicitly create the payment session on your backend, redirect the user to Opayo’s hosted payment page, and handle the post‑payment callback (webhook) back into your Repl. Replit works fine for development and light production, as long as you keep sensitive keys out of code and use persistent external storage for anything critical.
Opayo (formerly Sage Pay) is a UK payment gateway. Integrating it inside Replit means your Repl acts as the backend server responsible for:
You do not run Sage Pay inside Replit; you only talk to its real API using HTTPS.
In Replit:
This is a minimal working example using Express, following Opayo’s REST API patterns.
// server.js
import express from "express";
import fetch from "node-fetch";
const app = express();
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Load credentials from Replit Secrets
const vendor = process.env.OPAYO_VENDOR_NAME;
const apiKey = process.env.OPAYO_API_KEY;
const apiPassword = process.env.OPAYO_API_PASSWORD;
// Create a payment session
app.post("/create-session", async (req, res) => {
try {
const payload = {
amount: 1000, // amount in minor units (e.g., ÂŁ10.00)
currency: "GBP",
description: "Test Purchase",
customerFirstName: "John",
customerLastName: "Doe",
billingAddress: {
address1: "123 Example Street",
city: "London",
postalCode: "EC1A 1AA",
country: "GB"
},
entryMethod: "Ecommerce"
};
const response = await fetch("https://pi-test.sagepay.com/api/v1/transactions", {
method: "POST",
headers: {
Authorization: "Basic " + Buffer.from(apiKey + ":" + apiPassword).toString("base64"),
"Content-Type": "application/json"
},
body: JSON.stringify(payload)
});
const data = await response.json();
// The nextURL is where you redirect the user
return res.json({ redirectUrl: data._links.nextUrl.href });
} catch (err) {
console.error(err);
return res.status(500).send("Error creating session");
}
});
// Callback route Opayo redirects to after payment
app.post("/opayo-callback", (req, res) => {
// Validate signature using Opayo docs
// req.body contains the transaction status
console.log("Opayo callback received:", req.body);
// Acknowledge receipt to Opayo
return res.send("OK");
});
// Bind to 0.0.0.0 so Replit can expose the server
app.listen(3000, "0.0.0.0", () => {
console.log("Server running on port 3000");
});
This is the correct, real‑world method: explicit server, explicit routes, explicit Opayo REST calls, and no magic behind the scenes. You run a normal web backend inside Replit and talk to Opayo exactly as you would from any other server.
1
A Replit web server (Node/Express, Flask, or FastAPI) can securely collect payment details in the browser using Sage Pay’s client-side encryption or hosted payment page, then send the encrypted payload to your server. The server uses your Sage Pay credentials stored in Replit Secrets to call Sage Pay’s REST API. This avoids handling raw card data and keeps compliance manageable. Replit simply hosts the app, binds to 0.0.0.0, and exposes the port publicly so customers can pay through a production URL.
// Node/Express example: sending a Sage Pay transaction request
import fetch from "node-fetch";
import express from "express";
const app = express();
app.use(express.json());
app.post("/pay", async (req, res) => {
const payload = req.body; // encrypted card data from frontend
const result = await fetch("https://pi-live.sagepay.com/api/v1/transactions", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Authorization": "Basic " + process.env.SAGEPAY_AUTH // vendor:password base64
},
body: JSON.stringify(payload)
});
res.json(await result.json());
});
app.listen(3000, "0.0.0.0");
2
You can run a live Replit server that receives Sage Pay webhooks when a transaction changes status (successful, failed, refunded). Webhooks are simple HTTP POST requests. Sage Pay will call your public Repl URL or Deployment URL. Inside Replit, you expose your server on a fixed port and verify each webhook message using Sage Pay’s signature rules. This setup keeps UI pages responsive while payment state updates happen in the background.
// Basic webhook endpoint with signature verification
app.post("/sagepay/webhook", (req, res) => {
const signature = req.headers["x-signature"];
const expected = processWebhookSignature(req.body, process.env.SAGEPAY_WEBHOOK_KEY);
if (signature !== expected) return res.status(401).end();
// Update order status in your external DB
res.status(200).end();
});
3
Replit is ideal for building a fast, isolated test environment for Sage Pay before shipping real payments. You run a mock checkout UI, connect it to Sage Pay’s test API, and inspect requests and responses in real time. Because Replit restarts processes, it is best used as a temporary sandbox for integration development rather than a production payment processor. Still, it enables rapid prototyping of full flows—checkout, encryption, backend call, webhook callback—within one Repl.
// Triggering your local webhook endpoint from Replit shell
curl -X POST https://your-repl-url.replit.app/sagepay/webhook \
-H "x-signature: test" \
-H "Content-Type: application/json" \
-d '{"Status":"OK"}'
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
Sage Pay callbacks fail because Replit URLs are not stable inbound endpoints. Your Repl sleeps, restarts, changes its public URL, and cannot expose a fixed HTTPS callback that Sage Pay can reach reliably. Sage Pay needs a permanent, always‑on, TLS‑valid URL, but a Repl’s runtime is not guaranteed to be online when Sage Pay sends the callback.
A Replit webserver only works while the Repl is actively running and bound to 0.0.0.0. The preview URL is a proxy, not a public webhook endpoint, and it may rotate or sleep. Payment gateways like Sage Pay expect a static HTTPS URL that cannot disappear. When your Repl pauses, the callback is sent into a dead connection, so Sage Pay reports failure.
import express from "express"
const app = express()
app.post("/sagepay", (req, res)=>{
res.send("OK") // Works only while Repl is awake!
})
app.listen(3000,"0.0.0.0")
2
CORS or mixed‑content errors happen because the browser blocks calls from your Replit frontend to Sage Pay. You must send payment requests from your Replit backend only, using HTTPS on both sides. The frontend should never call Sage Pay directly.
Expose a backend route in your Replit server, call that from the browser, and let the server make the HTTPS request to Sage Pay. Ensure your Replit URL is HTTPS to avoid mixed‑content.
// server.js
import express from "express";
import fetch from "node-fetch";
const app = express();
app.post("/pay", async (req,res)=>{
const r = await fetch("https://pi-live.sagepay.com/api/v1/transactions", {
method:"POST",
headers:{ "Content-Type":"application/json" },
body: JSON.stringify(req.body)
});
res.json(await r.json());
});
app.listen(3000,"0.0.0.0");
3
Replit deployments often fail to load Sage Pay keys because deployment environments don’t automatically copy Secrets from the Repl runtime. Secrets must be explicitly added in the Deployment settings, and any mismatch in key names, missing variables, or use of reserved characters makes the Sage Pay client think no credentials exist.
Replit runs your code in two different places: the Editor run and the Deployment. Each has its own environment. If your Sage Pay keys only exist in the Repl’s Secrets panel, the deployment won’t see them. Sage Pay also requires exact variable names and correct formatting; an extra space or wrong name means the variable resolves as empty.
const vendor = process.env.SAGEPAY_VENDOR; // Must exist in Deployment env
if (!vendor) throw new Error("Missing SagePay vendor ID");
Â
Developers often set Sage Pay (Opayo) callback URLs that don’t match the actual public URL of the running Repl. Replit only exposes routes through the generated HTTPS URL or the Deployment URL, never through localhost. If the callback doesn’t point to that public URL, Sage Pay can’t POST the payment result back, leaving payments in a “pending” state.
app.post("/sagepay/callback", (req, res) => {
// verify payload, update order, send 200 OK
res.send("OK");
});
Â
Placing Sage Pay vendor names, keys, or encryption passwords directly in code causes accidental exposure because Repls are forkable and readable. Replit’s correct approach is storing all sensitive data in Secrets, which appear inside the app as environment variables that won’t leak in forks, logs, or Git history.
const vendor = process.env.SAGEPAY_VENDOR; // from Replit Secrets
const key = process.env.SAGEPAY_KEY; // sensitive
Â
Sage Pay requires HTTPS for redirects and notifications. Replit already provides HTTPS for the main public URL, but the mistake happens when devs test against raw ports like http://0.0.0.0:3000 inside the browser. Sage Pay will reject these non‑HTTPS endpoints, causing failed payments or rejected requests.
app.listen(3000, "0.0.0.0"); // Replit maps this to an HTTPS public URL
Â
Some developers trust the callback body directly without performing Sage Pay's required signature or encryption checks. On Replit, this is particularly risky because public URLs are easily discoverable. Without validating Sage Pay’s signature, any actor could POST fake “payment successful” data to your callback endpoint.
// Pseudocode placeholder: perform real Opayo signature/decryption per docs
if (!isValidSagePay(req.body)) return res.status(400).send("Invalid");
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.Â