What SolRUO provides you
After your brand is approved and onboarded to the SolRUO Stripe organization, our team will send you the following credentials. Treat the secret values as you would any production secret.
| Credential | Where it lives | Example |
|---|---|---|
| CLIENT_SLUG | Server env var | your-brand-slug |
| CLIENT_ACCOUNT_ID | Server env var | acct_1XXXXXXXXX |
| STRIPE_PUBLISHABLE_KEY | Client (safe to expose) | pk_live_XXXX |
How the flow works
- 1. Customer clicks Checkout on your site.
- 2. Your backend calls POST /api/public/create-payment on SolRUO with the order amount and your credentials.
- 3. SolRUO creates a Stripe PaymentIntent on the platform, routes funds to your connected account, deducts the SolRUO platform fee, and returns a clientSecret.
- 4. Your frontend mounts Stripe Elements with that secret and confirms the payment client-side.
- 5. Stripe webhooks fire to your own account so you can fulfill the order.
API reference
One endpoint. CORS is enabled, but you should always call it server-to-server so your credentials never reach the browser.
POST https://solruo.com/api/public/create-payment
Content-Type: application/json
{
"amount": 9900, // integer, cents (USD), required
"currency": "usd", // optional, defaults to "usd"
"clientSlug": "your-brand-slug", // provided by SolRUO
"clientAccountId": "acct_...", // provided by SolRUO
"metadata": { "order_id": "123" } // optional, string values only
}
→ 200 OK
{
"clientSecret": "pi_3..._secret_...",
"paymentIntentId": "pi_3...",
"applicationFeeAmount": 1144
}Add your environment variables
Drop these into .env.local (Next.js), .env (Node/Express), or your hosting provider's secret store.
# .env.local — provided by SolRUO during onboarding
SOLRUO_API_URL=https://solruo.com/api/public/create-payment
SOLRUO_CLIENT_SLUG=your-brand-slug
SOLRUO_CLIENT_ACCOUNT_ID=acct_XXXXXXXXXXXXXXXX
# Stripe — platform publishable key (safe to expose in client code)
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=pk_live_XXXXXXXXXXXXXXXXXXXXXXXX
Install Stripe on the frontend
npm install @stripe/stripe-js @stripe/react-stripe-js
# or
pnpm add @stripe/stripe-js @stripe/react-stripe-jsAdd the backend checkout route
This is the only piece of server code you need. Pick the snippet for your stack.
// app/api/checkout/route.ts (Next.js App Router)
import { NextResponse } from "next/server";
export async function POST(req: Request) {
const { amount } = await req.json(); // amount in cents
if (!Number.isInteger(amount) || amount < 100) {
return NextResponse.json({ error: "Invalid amount" }, { status: 400 });
}
const res = await fetch(process.env.SOLRUO_API_URL!, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
amount,
currency: "usd",
clientSlug: process.env.SOLRUO_CLIENT_SLUG,
clientAccountId: process.env.SOLRUO_CLIENT_ACCOUNT_ID,
}),
});
const data = await res.json();
if (!res.ok) {
return NextResponse.json({ error: data.error ?? "Payment failed" }, { status: 502 });
}
// Return only the clientSecret to the browser
return NextResponse.json({ clientSecret: data.clientSecret });
}
// server.js (Node + Express)
import express from "express";
const app = express();
app.use(express.json());
app.post("/api/checkout", async (req, res) => {
const { amount } = req.body; // cents
if (!Number.isInteger(amount) || amount < 100) {
return res.status(400).json({ error: "Invalid amount" });
}
const r = await fetch(process.env.SOLRUO_API_URL, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
amount,
currency: "usd",
clientSlug: process.env.SOLRUO_CLIENT_SLUG,
clientAccountId: process.env.SOLRUO_CLIENT_ACCOUNT_ID,
}),
});
const data = await r.json();
if (!r.ok) return res.status(502).json({ error: data.error });
res.json({ clientSecret: data.clientSecret });
});
app.listen(3000);
Mount the checkout component
A drop-in React component using Stripe's PaymentElement. Works in any React app — Vite, Next.js, Remix, etc.
// components/SolruoCheckout.tsx
import { useEffect, useState } from "react";
import { loadStripe } from "@stripe/stripe-js";
import {
Elements,
PaymentElement,
useStripe,
useElements,
} from "@stripe/react-stripe-js";
const stripePromise = loadStripe(import.meta.env.VITE_STRIPE_PUBLISHABLE_KEY!);
// In Next.js use: process.env.NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY!
export function SolruoCheckout({ amountInCents }: { amountInCents: number }) {
const [clientSecret, setClientSecret] = useState<string | null>(null);
useEffect(() => {
fetch("/api/checkout", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ amount: amountInCents }),
})
.then((r) => r.json())
.then((d) => setClientSecret(d.clientSecret));
}, [amountInCents]);
if (!clientSecret) return <div>Loading secure checkout…</div>;
return (
<Elements stripe={stripePromise} options={{ clientSecret, appearance: { theme: "night" } }}>
<CheckoutForm />
</Elements>
);
}
function CheckoutForm() {
const stripe = useStripe();
const elements = useElements();
const [submitting, setSubmitting] = useState(false);
const [error, setError] = useState<string | null>(null);
const handleSubmit = async (e: React.FormEvent) => {
e.preventDefault();
if (!stripe || !elements) return;
setSubmitting(true);
setError(null);
const { error } = await stripe.confirmPayment({
elements,
confirmParams: { return_url: `${window.location.origin}/order/success` },
});
if (error) setError(error.message ?? "Payment failed");
setSubmitting(false);
};
return (
<form onSubmit={handleSubmit} className="space-y-4">
<PaymentElement />
{error && <div className="text-red-500 text-sm">{error}</div>}
<button
disabled={!stripe || submitting}
className="w-full rounded-md bg-black px-4 py-3 text-white"
>
{submitting ? "Processing…" : "Pay now"}
</button>
</form>
);
}
Then use it from any page:
<SolruoCheckout amountInCents={9900} />Or use plain HTML / no framework
<!-- Plain HTML / vanilla JS checkout -->
<!doctype html>
<html>
<body>
<form id="payment-form">
<div id="payment-element"></div>
<button id="submit">Pay</button>
<div id="error" style="color:red"></div>
</form>
<script src="https://js.stripe.com/v3/"></script>
<script type="module">
const stripe = Stripe("pk_live_XXXXXXXXXXXXXXXXXXXX"); // platform publishable key
const res = await fetch("/api/checkout", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ amount: 9900 }), // $99.00
});
const { clientSecret } = await res.json();
const elements = stripe.elements({ clientSecret });
elements.create("payment").mount("#payment-element");
document.getElementById("payment-form").addEventListener("submit", async (e) => {
e.preventDefault();
const { error } = await stripe.confirmPayment({
elements,
confirmParams: { return_url: window.location.origin + "/success" },
});
if (error) document.getElementById("error").textContent = error.message;
});
</script>
</body>
</html>
Handle the success redirect
After the customer confirms payment Stripe redirects to your return_url with the PaymentIntent ID attached.
// app/order/success/page.tsx — verify the payment server-side
export default async function SuccessPage({
searchParams,
}: {
searchParams: { payment_intent?: string; payment_intent_client_secret?: string };
}) {
const piId = searchParams.payment_intent;
// Optional: look up the PaymentIntent via your own backend
// before marking the order as paid. Stripe will also send
// a webhook (payment_intent.succeeded) which is the most reliable signal.
return (
<main className="p-10">
<h1 className="text-2xl">Order received</h1>
<p>Reference: {piId}</p>
</main>
);
}
Listen for webhooks (recommended)
Webhooks are the only reliable way to know an order was paid. Configure a webhook endpoint inside your own Stripe Connect account dashboard pointing at the route below, and subscribe to payment_intent.succeeded.
// app/api/stripe/webhook/route.ts
import Stripe from "stripe";
import { NextResponse } from "next/server";
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!); // your OWN account's secret key
export async function POST(req: Request) {
const sig = req.headers.get("stripe-signature")!;
const body = await req.text();
let event: Stripe.Event;
try {
event = stripe.webhooks.constructEvent(
body,
sig,
process.env.STRIPE_WEBHOOK_SECRET!,
);
} catch (err) {
return new NextResponse("Bad signature", { status: 400 });
}
if (event.type === "payment_intent.succeeded") {
const pi = event.data.object as Stripe.PaymentIntent;
// mark order as paid, fulfill, send receipt, etc.
console.log("Paid:", pi.id, pi.amount);
}
return NextResponse.json({ received: true });
}
WooCommerce stores
The official WooCommerce Stripe plugin does not support Stripe Connect destination charges, so it cannot route funds into your SolRUO connected account. Use a custom SolRUO gateway plugin instead.
We provide a starter plugin (solruo-gateway.php) that adds a SolRUO payment method, creates a PaymentIntent via the SolRUO API, hosts a Stripe Elements payment page on your site, and listens for Stripe webhooks.
Set the webhook endpoint in your Stripe dashboard to:
https://your-site.com/wc-api/solruo_webhookPlace the plugin file in your WordPress install and enter the SolRUO credentials on WooCommerce → Settings → Payments → SolRUO.
Test, then go live
- While SolRUO has your account in test mode, use Stripe's test card 4242 4242 4242 4242, any future expiry, any CVC, any ZIP.
- When SolRUO flips your account to live, swap pk_test_… for pk_live_… on the frontend. No backend changes needed.
- Confirm an end-to-end $1.00 charge in production before announcing checkout.
Need help?
Email support@solruo.com with your CLIENT_SLUG and we will respond within one business day. For Stripe-specific questions (disputes, payouts, tax) you can also contact Stripe support directly from your connected-account dashboard.