DEV Community

Built2WinWeb
Built2WinWeb

Posted on Originally published at built2winweb.com on

How to Add Stripe Checkout to a Custom PHP Website (No Plugins)

How to Add Stripe Checkout to a Custom PHP Website (No Plugins)

💳 PHP · Updated June 2026 · 12 min read · by Jacob Campbell

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-php
Enter fullscreen mode Exit fullscreen mode

Then load it at the top of your checkout script:

require_once __DIR__. '/vendor/autoload.php';
\Stripe\Stripe::setApiKey(getenv('STRIPE_SECRET_KEY'));
Enter fullscreen mode Exit fullscreen mode

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]);
Enter fullscreen mode Exit fullscreen mode

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;
});
Enter fullscreen mode Exit fullscreen mode

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);
Enter fullscreen mode Exit fullscreen mode

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('hello@yoursite.com', 'Your Business');
    $mail->addAddress($email, $name);
    $mail->Subject = 'Payment received — thank you!';
    $mail->Body = "Hi $name, your order is confirmed.";
    $mail->send();
}
Enter fullscreen mode Exit fullscreen mode

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

Top comments (0)