How to Add Stripe Checkout to a Custom PHP Website (No Plugins)
Stripe is the cleanest payments API available, and wiring it straight into PHP means no monthly SaaS fees, no WooCommerce bloat, and none of Shopify’s per-transaction cut. What follows is the exact implementation running in real BuiltToWinWeb client stores: plain PHP, the official Stripe SDK, secure webhooks, and automated email confirmations. You’ll see how the pieces fit together — checkout session, redirect, webhook verification, fulfilment — so you can take live payments without handing a slice to a platform. Everything here is production code, not a throwaway demo.
Key facts
- 0% — Platform fee / txn
- 98 — Checkout Lighthouse
- 0.6s — Checkout LCP
- $0/mo — Platform cost
Why native PHP + Stripe beats any page builder
Shopify charges 0.5–2% per transaction on top of Stripe’s own fee. WooCommerce adds 14+ plugin dependencies that drag your checkout LCP to 3.8s. A custom PHP integration delivers a checkout that loads in under 0.6s and keeps every cent of margin.
- Zero platform transaction fees — just Stripe’s 2.9% + 30¢.
- Checkout Lighthouse score: 98 vs Shopify’s typical 61.
- Full webhook control — custom fulfilment, inventory, email.
- No recurring ecommerce-platform subscription.
- You own the code, host anywhere, migrate freely.
Step 1 — install the Stripe PHP SDK
Composer is the cleanest approach. If your server doesn’t support Composer, download the SDK ZIP and drop it in your project root.
composer require stripe/stripe-phpThen load it at the top of your checkout script:
require_once __DIR__ . '/vendor/autoload.php';
\Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET_KEY'));Step 2 — create a Checkout session (server-side)
Never put your secret key in the browser. Create a server-side endpoint the frontend POSTs to:
<?php
require_once __DIR__ . '/vendor/autoload.php';
\Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET_KEY'));
$session = \Stripe\Checkout\Session::create([
'payment_method_types' => ['card'],
'line_items' => [[
'price_data' => [
'currency' => 'usd',
'unit_amount' => 175000,
'product_data' => ['name' => 'Business Pro Website'],
],
'quantity' => 1,
]],
'mode' => 'payment',
'success_url' => 'https://yoursite.com/success?session_id={CHECKOUT_SESSION_ID}',
'cancel_url' => 'https://yoursite.com/pricing',
]);
header('Content-Type: application/json');
echo json_encode(['url' => $session->url]);Step 3 — redirect the user from the frontend
A simple fetch call on your pricing-page button:
document.getElementById('buy-btn').addEventListener('click', async () => {
const res = await fetch('/create-checkout-session.php', { method: 'POST' });
const data = await res.json();
window.location.href = data.url;
});Step 4 — handle webhooks (order fulfilment)
Stripe POSTs to your webhook endpoint when payment completes. This is where you trigger email, update inventory and record the order — NOT on the success page (the user may never reach it).
<?php
$payload = file_get_contents('php://input');
$sig = $_SERVER['HTTP_STRIPE_SIGNATURE'];
$secret = getenv('STRIPE_WEBHOOK_SECRET');
try {
$event = \Stripe\Webhook::constructEvent($payload, $sig, $secret);
} catch (\Exception $e) {
http_response_code(400); exit;
}
if ($event->type === 'checkout.session.completed') {
$session = $event->data->object;
fulfill_order($session);
}
http_response_code(200);Register the webhook URL in the Stripe dashboard under Developers → Webhooks. Test locally with stripe listen --forward-to localhost/webhook.php.
Step 5 — send a confirmation email with PHPMailer
Inside your fulfill_order() function, get the customer email from the session and run PHPMailer:
function fulfill_order($session) {
$email = $session->customer_details->email;
$name = $session->customer_details->name;
$mail = new PHPMailer\PHPMailer\PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.yourhost.com';
$mail->Username = getenv('SMTP_USER');
$mail->Password = getenv('SMTP_PASS');
$mail->setFrom('[email protected]', 'Your Business');
$mail->addAddress($email, $name);
$mail->Subject = 'Payment received — thank you!';
$mail->Body = "Hi $name, your order is confirmed.";
$mail->send();
}Security checklist
- Store keys in environment variables — never hard-code them in PHP files.
- Always verify Stripe webhook signatures with
constructEvent(). - Use HTTPS everywhere — Stripe requires it.
- Idempotency: check whether the order already exists before processing.
- Rate-limit
/create-checkout-session.php(e.g. 10 requests/hour per IP).
Custom PHP + Stripe vs Shopify vs WooCommerce
| Metric | Custom PHP + Stripe | Shopify | WooCommerce |
|---|---|---|---|
| Checkout LCP | 0.6s | 1.9s | 2.8s |
| Lighthouse score | 98 | 61 | 55 |
| Platform fee / txn | 0% | 0.5–2% | 0%* |
| Monthly platform cost | $0 | $39–399 | $0* |
| Plugin dependencies | 0 | n/a | 14+ |
| Code ownership | 100% | 0% | ~60% |
Real business impact
On a store doing $50,000/month in sales, Stripe’s 2.9% + 30¢ is unavoidable. But Shopify’s extra 0.5–2% platform fee costs $250–1,000 more per month. Custom PHP removes that.
- Shopify Advanced ($399/mo) + 0.5% on $50,000 = $649/mo in platform costs.
- Custom PHP + Stripe = $0/mo in platform costs (just Stripe’s standard fees).
- Break-even on a $5,600 store: under 9 months.
- Checkout pages load 3× faster = measurably lower cart-abandonment.
The math is simple: if you process more than $15,000/month, a custom PHP store pays for itself in under a year.
Sources & further reading
Related services
Frequently asked questions
Do I need Composer to use Stripe with PHP?
Composer is recommended but not required. You can download the Stripe PHP SDK as a ZIP and include it manually with require_once; Composer just makes updates easier.
Is it safe to process payments without a platform like Shopify?
Yes. Stripe is PCI-DSS Level 1 certified. Your server never handles raw card numbers — Stripe’s JS tokenises them client-side, and your PHP only receives a session ID.
How do I test Stripe without charging real cards?
Use Stripe test mode with an sk_test_ key. Use test card 4242 4242 4242 4242 with any future expiry and any 3-digit CVC.
Can I add subscriptions with this approach?
Yes. Change the Checkout session mode from 'payment' to 'subscription' and pass a recurring price ID instead of price_data; Stripe handles the billing cycles.
How much does a custom Stripe store cost?
BuiltToWinWeb ecommerce stores are a flat $5,600 one-time fee — no monthly platform costs and you own the code forever.
Why is a custom checkout faster than Shopify?
No theme runtime, no app scripts and no plugin bloat — just the code the checkout needs, so LCP lands near 0.6s versus ~1.9s on Shopify.
Do you build custom Stripe stores?
Yes — I build custom PHP ecommerce with native Stripe, webhooks, email confirmation and 98+ Lighthouse, typically delivered in 3–4 weeks.
Want a custom Stripe store built for you?
BuiltToWinWeb builds custom PHP ecommerce stores with native Stripe integration, 98+ Lighthouse scores and zero monthly platform fees. One flat fee — you own the code forever, usually delivered in 3–4 weeks.
Get my free quote