Stripe

The Stripe plugin (plg_solidshoppayment_stripe) adds Stripe’s Payment Element to your Solidshop checkout. One integration surfaces every payment method you have enabled in your Stripe account — cards with 3-D Secure, Apple Pay and Google Pay, Klarna, Affirm, Afterpay/Clearpay, iDEAL, SEPA Direct Debit, ACH, and more — picked automatically for each visitor based on their region, currency, and device.

The plugin ships under GPL-3 and talks to Stripe’s PaymentIntents API server-side; the browser only ever sees your publishable key. Stripe Connect (charging on behalf of a connected account) is supported out of the box. See the Stripe extension page for the high-level feature overview.

Requirements

  • Joomla 6.x or later
  • PHP 8.4 or later
  • Solidshop 1.3.1 or later — the installer refuses to run against an older core, so update Solidshop first if you are behind. 1.3.1 is what ships the Webhook URL field and the payment entries the plugin writes to the order’s Activity Timeline
  • A Stripe account — sign up here if you don’t have one yet
  • HTTPS on your storefront — Stripe requires it for live payments

Installation

Download the plugin

Download plg_solidshoppayment_stripe.zip from the Downloads page — it’s available while your Stripe plugin subscription is active, and updates arrive through the standard Joomla updater.

Install via the Extension Manager

In your Joomla admin, go to System → Install → Extensions. Drag the ZIP file into the upload area or click “Browse for file” and select it. Joomla installs the plugin and registers the solidshoppayment group entry — no Composer step required.

Enable the plugin

Go to System → Manage → Plugins, filter by the solidshoppayment type, and enable Solidshop Payment — Stripe. The plugin is disabled by default after install — until you enable it, Stripe won’t appear at checkout.

Get your Stripe API keys

Stripe authenticates the plugin with a publishable key and a secret key pair. You’ll need two pairs — one for test mode and one for live — and you can store both simultaneously.

Open the Stripe dashboard

Go to dashboard.stripe.com → Developers → API keys and log in with the Stripe account that will receive your payouts.

Copy both key pairs

With the dashboard’s Test mode toggle on, copy the test Publishable key (pk_test_…) and Secret key (sk_test_…). Toggle test mode off and copy the live pair (pk_live_… / sk_live_…) the same way.

Configure the plugin

Stripe configuration lives at the store level — each store has its own keys, so you can run a separate Stripe account per storefront in a multi-store install.

Open your store’s Payments tab

Go to Solidshop → Stores, open the store you want to configure, and switch to the Payments tab. Tick the Stripe row to enable it for this store.

Pick test mode or live

The Test mode switch defaults to Yes so accidental charges aren’t possible on a fresh install. Leave it on Yes while you run test checkouts; flip it to No when you’re ready to accept real payments.

Both key pairs are stored in parallel — the plugin reads the test pair while test mode is on, and the live pair when it’s off. If the pair for the active mode is missing, Stripe is automatically hidden at checkout.

Paste your keys

In test mode, fill the test Publishable Key and Secret Key fields. Outside test mode, fill the live pair. Both are required when the matching mode is active — Solidshop refuses to save the form otherwise.

If you charge on behalf of a Stripe Connect account, enter its account ID (acct_…) in the optional Connected Account ID field. Leave it empty to charge your own account directly.

Optional — set a surcharge fee

If you want to pass Stripe’s processing cost to the customer, enter a flat amount in the Fee field. It appears as a separate line in the cart total when Stripe is selected at checkout. Leave it at 0 to absorb the fee yourself.

Save, then set up the webhook

Save the store, then continue with Webhooks & payment reconciliation below — the webhook is not optional for Stripe: redirect-based methods (Klarna, iDEAL, …) and bank debits are only confirmed through it.

Webhooks & payment reconciliation

Card payments are usually confirmed inline, before the shopper leaves your checkout. Everything else is decided after they leave — a Klarna or iDEAL approval that happens on the provider’s site, or a SEPA/ACH bank debit that clears days later. Stripe reports those outcomes through webhooks. The plugin verifies each event’s signature and reconciles two of them:

  • payment_intent.succeeded — the payment cleared; the plugin checks the captured amount and currency against the order, marks it Paid, queues the confirmation email, and records the capture on the order’s Activity Timeline together with the PaymentIntent id. Every payment is logged there — the entry names the webhook when reconciliation happened after checkout, so you can tell the two apart at a glance.
  • charge.refunded — a refund was issued at Stripe (including one made in the Stripe dashboard); the order moves to Refunded or Partially refunded.
Copy the Webhook URL

In Solidshop → Stores, open your store, go to Payments → Stripe, and copy the read-only Webhook URL field. It looks like https://your-site.example/index.php?option=com_solidshop&task=payment.callback&payment=stripe&store_id=1 and is unique per store. The field only appears once the store is saved — the URL carries the store ID.

Create the endpoint in Stripe

In the Stripe dashboard → Developers → Webhooks, click Add endpoint, paste the Webhook URL, and subscribe it to the payment_intent.succeeded and charge.refunded events. Create the endpoint in the mode you’re configuring — test and live each need their own endpoint and secret.

Stripe also asks you to pick an API version for the endpoint. Any current version works — take the default your account is already on. The version only shapes the event payload Stripe sends, and the plugin reads just the long-stable fields (the payment intent’s id, amount and metadata; the charge’s payment intent, currency and cumulative refunded amount). It pins its own version independently for the API calls it makes, so the two never have to match.

Paste the signing secret back

Stripe shows a signing secret (whsec_…) for the new endpoint. Copy it into the store’s Webhook Signing Secret field for the matching mode and save. The plugin uses it to verify the signature on every incoming event — a store with no signing secret on file rejects all of them.

Testing webhooks on a local site. Stripe can’t reach a localhost URL. For development, use the Stripe CLI: stripe listen --forward-to your Webhook URL prints a temporary signing secret — paste that into the store while you test.

Test with Stripe test cards

Place a test checkout

With test mode on, run a checkout on your storefront and pick Stripe. The Payment Element opens in a dialog — pay with the classic test card 4242 4242 4242 4242 (any future expiry, any CVC). Stripe’s testing guide lists numbers that decline, trigger 3-D Secure, and simulate every other payment method.

Verify the order

Open Solidshop → Orders and check the new order: payment status should be Paid, the payment method should be Stripe, and the recorded transaction ID (pi_…) should match the PaymentIntent in your Stripe dashboard. Solidshop queues the confirmation email at this point — provided your email queue task is running, you’ll see it arrive within the next minute.

Test a redirect method too. If you plan to offer Klarna, iDEAL, or another redirect-based method, run one test checkout with it — it exercises the webhook path end-to-end and catches a missing or mismatched signing secret before real money is involved.

Supported currencies

Stripe processes payments in 135+ currencies. The plugin reads your store’s currency and forwards it to Stripe verbatim — no conversion happens inside Solidshop. Which payment methods appear in the Payment Element depends on the currency; cards work with all of them.

Zero-decimal currencies. Stripe counts JPY, KRW, VND and other zero-decimal currencies in whole units, and KWD, BHD and other three-decimal currencies in thousandths. The plugin converts amounts automatically in both directions — a ¥1,500 order is sent to Stripe as 1500, not 150000. Display formatting in your storefront isn’t affected.

How the payment flow works

For developers and integrators, the high-level sequence at checkout looks like this:

  1. The customer places the order; Solidshop creates it in a pending state and the plugin opens a dialog, loading Stripe.js from Stripe’s CDN.
  2. The plugin calls back to com_ajax?plugin=stripe&group=solidshoppayment&step=createPaymentIntent. The server creates a Stripe PaymentIntent for the order total and returns its client secret; the Payment Element renders in the dialog.
  3. The customer confirms. Card payments resolve inline; redirect methods (Klarna, iDEAL, …) send the browser to the provider and return through a signed, token-protected return URL.
  4. For inline payments, the plugin calls back with step=confirmPayment. The server re-fetches the PaymentIntent from Stripe’s API — never trusting the browser — validates its status, amount, and currency, marks the order Paid, and enqueues the confirmation email. Bank debits that resolve as processing leave the order pending until the webhook confirms the money moved.
  5. For redirect and asynchronous payments, the payment_intent.succeeded webhook performs the same validation and marks the order Paid.

PaymentIntent creation and confirmation both happen server-side, so the client never sees your secret key or decides the payment outcome — only the publishable key is exposed to the browser.

Finding an order in the Stripe dashboard

Every charge the plugin creates carries the store name and the order reference as its Description — for example My store 5 — order 821b7a65 — so the Stripe Payments list is readable without opening each row. The same payment also carries order_id and order_reference under Metadata on the payment page, which is what you search when reconciling a Stripe payout against Solidshop orders.

Refunds

Refund orders without leaving Joomla: open the order in Solidshop → Orders and use the Refund action — full or partial, with an optional reason that is stored on the Stripe refund. The money moves at Stripe first; only a refund Stripe accepted is recorded locally, and the order moves to Refunded or Partially refunded automatically. Bank-debit refunds that Stripe reports as pending are recorded the same way — the money is on its way.

Refunds issued directly from the Stripe dashboard are picked up too: the charge.refunded webhook reconciles them into the order’s refund history, so the order in Solidshop and the charge in Stripe never drift apart. The refunded amount always matches Stripe exactly; on recent API versions Stripe omits the individual refund from the event, so a dashboard refund is filed without its refund id or reason — refund from Joomla when you want those recorded on the order.

Troubleshooting

Stripe doesn’t appear at checkout

  • Confirm the plugin is Enabled under System → Plugins.
  • Confirm Stripe is ticked in the Store → Payments tab.
  • Confirm the publishable and secret key are saved for the active mode — the plugin hides itself when either is missing, so a store switched to live with only test keys shows no Stripe option.

The payment dialog shows a loading error

  • An ad blocker or strict privacy proxy can block js.stripe.com — the plugin shows a “Could not load Stripe” message instead of a payment form. Whitelisting the domain fixes it.
  • Check the browser console — an invalid publishable key surfaces here.

Shoppers are asked to create a Link account

  • Stripe’s Link offers to save a shopper’s details whenever the Payment Element collects an email and phone number — which Klarna and the bank-debit methods require. The notice comes from Stripe, not Solidshop, and no Elements option suppresses it.
  • Turn Link off per account under Stripe → Settings → Payment methods. Weigh it up first: Link gives returning shoppers one-click checkout, but a buyer who chose Klarna being asked to open a different account mid-payment is a conversion risk.

Klarna / iDEAL / bank-debit orders stay Pending

  • These methods are confirmed only by the webhook. Confirm the endpoint exists in the Stripe dashboard for the active mode, points at this store’s Webhook URL, and subscribes to payment_intent.succeeded.
  • Confirm the Webhook Signing Secret for the active mode matches that endpoint — a wrong or missing secret makes the store reject every delivery (Stripe’s dashboard shows the failed attempts).
  • On a development or localhost site, webhooks can’t be delivered at all — use the Stripe CLI as described above.
  • Check the Solidshop payment log (solidshoppayment_stripe.php in your Joomla log directory) for rejected-webhook entries.

Order confirmation email doesn’t arrive

The plugin enqueues the confirmation email after Stripe confirms the payment, using the standard Solidshop email queue. If emails aren’t sending, the scheduler task is the most likely culprit — see Set up the email queue in the installation guide.

Going live

When you’re ready to accept real payments:

  1. Flip Test mode to No in the store’s Payments tab.
  2. Confirm the live Publishable Key and Secret Key fields are filled and saved.
  3. Create a live webhook endpoint in the Stripe dashboard and paste its signing secret into the live Webhook Signing Secret field — the test endpoint doesn’t carry over. See Webhooks & payment reconciliation.
  4. Place one final low-value real order with your own card — you can refund it from the Stripe dashboard immediately.
  5. Watch the first few real orders for unexpected currency or method issues; the Stripe dashboard’s Events log is the fastest place to spot problems.

That’s it — Stripe is live on your Solidshop storefront.