How to Add Stripe Checkout to a Custom PHP Website (No Plugins) – BuiltToWinWeb
EN ES FR DE IT PT ZH JA KO RU NL
← Back to all articles

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

Stripe is the cleanest payment API available. No monthly SaaS fees, no WooCommerce overhead, no Shopify transaction cuts. This is the exact implementation used on BuiltToWinWeb client stores — PHP, Stripe SDK, webhooks, and email confirmations.

Why Native PHP + Stripe Beats Every Page Builder

Shopify charges 0.5–2% per transaction on top of Stripe's own fee. WooCommerce adds 14+ plugin dependencies that slow your checkout page LCP to 3.8s. A custom PHP integration ships a checkout that loads in under 0.6s and keeps every penny of margin.

  • Zero platform transaction fees — only Stripe's 2.9% + 30¢
  • Checkout page Lighthouse score: 98 vs Shopify's typical 61
  • Full webhook control — custom fulfillment, inventory, email
  • No recurring subscription cost for the ecommerce platform
  • Own your code, host anywhere, migrate freely

Step 1 — Install the Stripe PHP SDK

Composer is the cleanest approach. If your host doesn't support Composer, download the SDK zip and drop it in your project root.

composer require stripe/stripe-php

Then 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 that 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, // $1,750 in cents
            '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 (Fulfillment)

Stripe sends a POST to your webhook endpoint when payment succeeds. This is where you trigger email, update inventory, and record the order — NOT on the success page (which users can skip).

<?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); // your custom function
}

http_response_code(200);

Register your webhook URL in the Stripe dashboard under Developers → Webhooks. Use the CLI locally: `stripe listen --forward-to localhost/webhook.php`.

Step 5 — Send a Confirmation Email via PHPMailer

Inside your `fulfill_order()` function, pull the customer email from the session and fire 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();
}

Platform Comparison — Custom PHP 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 \$50,000/month ecommerce store, Stripe's 2.9% + 30¢ is unavoidable. But Shopify's additional 0.5–2% platform fee costs \$250–\$1,000 per month extra. Custom PHP eliminates that.

  • Shopify Advanced (\$399/mo) + 0.5% fee on \$50k = \$649/mo platform cost
  • Custom PHP + Stripe = \$0/mo platform cost (just Stripe's standard fees)
  • Breakeven on a \$5,600 custom build: 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.

Security Checklist

  • Store keys in environment variables — never hardcode in PHP files
  • Always verify Stripe webhook signatures with `constructEvent()`
  • Use HTTPS everywhere — Stripe requires it
  • Idempotency: check if the order already exists before fulfilling (replay protection)
  • Rate-limit your `/create-checkout-session.php` endpoint (10 req/hr per IP)

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 file 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 tokenizes them client-side. Your PHP only receives a session ID.

How do I test Stripe without charging real cards?

Use Stripe test mode with key prefix sk_test_. Use test card 4242 4242 4242 4242 with any future expiry and any 3-digit CVC. Switch to live keys when ready to go live.

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 billing cycles automatically.

Want a Custom Stripe Store Built for You?

BuiltToWinWeb builds custom PHP ecommerce stores with native Stripe integration, Lighthouse 98+ scores, and zero monthly platform fees. Flat one-time fee — you own the code forever.

Stores typically ship in 3–4 weeks. Reply within 24 hours guaranteed.

Get a Free Quote

Benchmark data from controlled tests on identical Hostinger VPS hosting. WooCommerce plugin count measured on default WooCommerce 8.x install with Storefront theme.