Drupalwoo ☉

Integrating Drupal with Stripe for secure online payments

Adding payments to a Drupal website involves more than placing a card form on a checkout page. The site must create payment records, handle failed transactions, confirm successful charges, protect customer data, and keep Drupal’s order status aligned with Stripe’s event system.

Stripe is a practical choice for many Australian organisations because it supports Australian dollars, major card schemes, Apple Pay, Google Pay, recurring billing, refunds, and a range of fraud-prevention features. A Drupal integration can support online shops, membership sites, event registrations, donations, and paid content.

The implementation path depends on the Drupal distribution and commerce layer already in use. Drupal Commerce sites can usually start with a Stripe payment gateway module, while a custom Drupal application may need a controller, service, configuration form, and Stripe PHP SDK integration.

A sound payment workflow keeps sensitive card details outside Drupal wherever possible. Stripe-hosted Checkout and Stripe Elements reduce the amount of payment data handled by the site, simplify compliance work, and give developers clear tools for responding to successful or unsuccessful payments.

Choose the right Drupal payment architecture

For a Drupal Commerce store, the first option to investigate is a maintained Stripe gateway module compatible with the installed Drupal and Commerce versions. A module can provide payment method configuration, checkout integration, order transitions, refunds, and webhook handling without requiring the entire payment lifecycle to be built from scratch.

Review the module’s issue queue, release history, supported PHP versions, and Stripe API approach before installing it. A module that worked well for an older Drupal release may rely on deprecated APIs or lack support for newer payment intents. Installation should happen in a development environment using Composer, followed by configuration export and deployment through the normal Drupal workflow.

A custom integration is suitable when the website has unusual business rules, such as deposits, staged payments, external booking records, or a bespoke subscription model. In that situation, use Drupal services and dependency injection rather than placing Stripe calls directly inside a form submit handler. Store internal order IDs and Stripe identifiers together, while avoiding storage of card numbers or security codes.

Useful JavaScript patterns can help when customising the checkout interface, especially when the payment form needs to react to address, shipping, or coupon changes. Developers who maintain reusable front-end snippets may also find front-end examples useful when testing browser-side interactions around Drupal forms.

Configure Stripe accounts and environments

Create separate Stripe test and live keys, and keep both sets outside the codebase. Drupal’s settings.php file, environment variables, or a secrets manager can provide credentials at runtime. A configuration form may expose publishable settings to administrators, but secret keys must never be printed into page markup, committed to Git, or included in JavaScript.

The Stripe dashboard should be configured with the business identity, public support details, statement descriptor, bank account, and payout schedule. For an Australian business, set AUD as the primary transaction currency when appropriate and verify how Stripe handles settlement, conversion, and payout reporting. A Melbourne retailer selling internationally may charge in AUD while displaying converted prices, but the final currency and exchange-rate behaviour must be clear to customers.

Use test mode to create representative products, orders, discounts, refunds, and failed payments. Test cards should cover successful authorisation, declines, insufficient funds, authentication requirements, and expired cards. Do not test by placing real charges and then attempting manual reversals, because that can obscure reporting and create unnecessary operational work.

The website should also display accurate business and contact information. Australian customers commonly expect prices to include GST where applicable, and the Australian Consumer Law affects refund representations, cancellations, and descriptions of goods or services. Stripe processes the payment, but Drupal still needs to present legally and commercially accurate terms.

Build a reliable checkout flow

A basic payment sequence begins when Drupal creates an order in a pending state. The server then creates a Stripe Checkout Session or PaymentIntent using the trusted order total, currency, customer details, and metadata. The browser receives only the information needed to complete payment, such as a Checkout URL or client secret.

Never accept the amount from a hidden form field as the final price. Recalculate the total on the server from products, quantities, tax, shipping, discounts, and any membership rules. This prevents a customer from changing browser data before the payment request is sent. Metadata should include an internal order number rather than private customer information.

Stripe Checkout is generally the quickest route to a production-ready payment page. Stripe hosts the sensitive payment interface, while the Drupal site supplies branding, line-item information, success URLs, and cancellation handling. Payment Element provides more visual control and can be embedded into Drupal, but it requires more careful JavaScript, form-state, and error-state management.

The success page is useful for customer feedback, yet it should not be treated as proof of payment. A customer can close the browser before returning, revisit a URL, or manipulate query parameters. The authoritative order transition should happen after Drupal verifies a Stripe webhook event.

Handle webhooks and order states

Configure a webhook endpoint that accepts relevant Stripe events, such as payment intent success, payment failure, checkout completion, charge refund, and subscription changes when recurring billing is used. Verify the Stripe-Signature header with the endpoint secret before processing the request. A webhook body that cannot be verified must be rejected.

Webhook processing should be idempotent. Stripe may retry delivery, and the same event must not create duplicate orders, grant access twice, or send repeated fulfilment messages. Save the Stripe event ID after successful processing, check it before acting again, and use a queue for work that does not need to happen during the HTTP request.

A robust state model separates “payment authorised”, “payment captured”, “payment failed”, “refunded”, and “partially refunded” where the business needs that detail. Drupal Commerce order states should reflect operational reality rather than simply changing to “completed” when a checkout session is created.

If a payment succeeds but the webhook arrives late, the order should remain safely pending until reconciliation occurs. Scheduled checks against Stripe can identify records that have an unexpected status. Administrators should have a clear way to inspect the internal order ID, Stripe payment ID, webhook history, and any error message without exposing secret payment data.

Protect customer data and meet Australian requirements

Payment integration is part of the site’s broader security design. Enforce HTTPS across the entire domain, use secure cookies, apply Drupal security updates promptly, restrict administrative permissions, and protect webhook endpoints from accidental exposure. Content Security Policy and carefully reviewed third-party scripts can reduce browser-side risk.

Using Stripe-hosted pages or Stripe Elements can reduce PCI DSS scope, but it does not eliminate responsibility. The organisation still needs appropriate access control, vulnerability management, incident procedures, payment-page monitoring, and documented handling of cardholder data. Staff should understand which payment details may be recorded in support tickets or order notes.

The Privacy Act 1988 and the Australian Privacy Principles are relevant when the checkout collects names, addresses, phone numbers, email addresses, and purchase history. The privacy policy should explain the role of Stripe and other processors, the purpose of data collection, retention practices, and overseas disclosures where relevant. A Sydney-based business serving customers nationwide may also need clear processes for access and correction requests.

Avoid placing full card data in Drupal logs, analytics events, email notifications, or debugging output. Redact Stripe responses before logging them, and give support staff access to masked identifiers only. If the site uses marketing consent, keep it separate from the legal necessity of processing an order and make the preference explicit.

Test real-world payment scenarios

Testing should cover the complete path from cart calculation through webhook delivery and fulfilment. Include guest checkout, registered customers, invalid addresses, coupon changes, tax changes, stock depletion, abandoned sessions, duplicate submissions, browser refreshes, and payment retries. Check that a failed card does not create a fulfilable order.

Australian delivery rules deserve specific attention. Test postcode validation for Sydney, Brisbane, Perth, and regional areas, along with shipping rates that vary by state or remote location. Verify that AUD formatting, GST calculations, invoice numbers, and refund amounts are consistent between Drupal, Stripe, customer emails, and accounting exports.

Run webhook tests with delayed delivery and repeated events. Temporarily disable a queue worker or endpoint and confirm that Stripe retries safely. Test an administrator refund in Stripe and confirm that Drupal updates the order without accidentally restoring stock or access in an incorrect way.

Before launch, complete a small live transaction using the lowest practical amount and verify the payout, statement descriptor, customer receipt, order status, and accounting record. Remove test products and keys from the production environment, then document the rollback process and the people responsible for responding to payment incidents.

Compare implementation options

The best approach depends on the required level of control, the team’s Drupal experience, and how much payment logic already exists in Drupal Commerce. Hosted Checkout is often preferable for a standard shop, while Payment Element suits a branded flow that still delegates card handling to Stripe. A custom API integration should be reserved for business requirements that established modules cannot support.

Approach Drupal effort Payment-page control Compliance exposure Suitable use
Stripe-hosted Checkout Low Limited to moderate branding Lower Standard products, donations, event tickets
Payment Element Moderate High Moderate Branded Commerce checkout with flexible payment methods
Drupal Commerce Stripe module Low to moderate Depends on module Depends on configuration Stores already using Drupal Commerce
Custom Stripe API service High Full Highest operational responsibility Bespoke billing, deposits, or complex workflows

A module-led implementation still needs review and testing. Confirm that its webhook endpoint verifies signatures, its order updates are idempotent, and its refund behaviour matches the business process. For a small Australian organisation, reducing custom code can make ongoing security maintenance easier than building a completely independent payment service.

Document the configuration, test cards, webhook events, failure responses, refund procedures, and live-key ownership. A short runbook helps a site administrator resolve routine issues without granting broad access to Stripe or Drupal. Operational notes can be kept alongside other site administration resources, including internal updates shared through Drupal community notes.

Maintain the integration after launch

Payment systems need routine maintenance because Drupal core, contributed modules, PHP, browser APIs, and Stripe’s API can all change. Subscribe to security advisories, review module releases, monitor deprecation notices, and schedule testing before upgrading Drupal or the Commerce stack.

Monitor successful and failed payment rates, webhook delivery, checkout abandonment, refund volumes, and unusual spikes in declined transactions. Stripe’s dashboard is useful for payment-level visibility, while Drupal logs and order reports explain what happened inside the site. Alerts should distinguish a customer’s declined card from a broken webhook endpoint.

Review access to Stripe and Drupal administration regularly. Remove former staff, rotate secrets after suspected exposure, and keep live credentials separate from staging credentials. A staging environment should never send emails to real customers or accidentally create live PaymentIntents.

With server-side amount validation, verified webhooks, careful privacy practices, and realistic Australian payment testing, Drupal can provide a dependable connection to Stripe. The result is a checkout that supports customers clearly while giving editors, developers, and administrators the records they need to operate the website safely.