Transform Learning with a Powerful Enterprise LMS

Learn more
WordPress LMS

Tutor LMS Payment Gateway Architecture (Ollyo PaymentHub)

How a gateway plugs into Tutor LMS native e-commerce: the gateway, config and payment classes, the registration filters, the shared webhook route, the order data to return, and renewals and refunds.

Learn more about this topic with AI

Gemini opens with the prompt copied - paste it into the chat to start.

Diagram-style illustration of a payment gateway adapter connecting Tutor LMS checkout, orders and webhooks to a payment provider

Tutor LMS payment gateway development means plugging three classes into Tutor's native e-commerce: a gateway class that extends Tutor\PaymentGateways\GatewayBase, a config class that extends Ollyo\PaymentHub\Core\Payment\BaseConfig, and a payment class that extends Ollyo\PaymentHub\Core\Payment\BasePayment. You register the first two through the tutor_payment_gateways_with_class and tutor_gateways_with_class filters, and Tutor handles the cart, orders, enrolment and the webhook route.

This article walks through that architecture as Themeum's own Tutor Stripe add-on uses it, so you can judge what a custom or regional gateway involves before you build one. It applies only when Tutor's native e-commerce is the monetisation engine; WooCommerce and EDD checkouts use their own gateway systems.

Checked against the source of Tutor LMS 4.1.3, Tutor LMS Pro 4.1.3 and Tutor Stripe 1.0.9 (October 2026). The gateway framework classes carry @since 3.0.0 tags, the release that introduced native e-commerce.

The three layers: Tutor, PaymentHub and the provider

The design separates WordPress concerns from payment-provider concerns:

LayerClassOwns
Tutor adapterGatewayBase subclass, for example TutorStripe\StripeGatewayNaming the payment and config classes; loading the provider SDK's autoloader
ConfigurationBaseConfig subclass, for example TutorStripe\StripeConfigReading saved settings, exposing keys, mode, success, cancel and webhook URLs, and is_configured()
Provider logicBasePayment subclass, for example Ollyo\PaymentHub\Payments\Stripe\StripeBuilding the checkout, redirecting, verifying webhooks, recurring charges and refunds

The Ollyo\PaymentHub framework ships inside Tutor core, under ecommerce/PaymentGateways/Paypal/src, because the bundled PayPal gateway uses it. Its PaymentHub class takes a payment class name and a config class name, builds the config with createConfig(), injects it into the payment object, calls check() and throws InvalidConfigurationException if the check fails, then calls setup(). For the wider plugin structure, see our Tutor LMS architecture overview.

How Tutor finds a gateway

Core keeps a map from a gateway key to its classes. Ecommerce::payment_gateways_with_ref() starts with PayPal and runs the map through tutor_payment_gateways_with_class. Checkout and the webhook handler then pass the result through a second filter, tutor_gateways_with_class, which receives the requested key as its second argument. Tutor Stripe hooks both, each returning an entry of this shape:

'stripe' => array(
    'gateway_class' => StripeGateway::class,
    'config_class'  => StripeConfig::class,
),

A gateway is offered at checkout only when it is active in the payment settings and Ecommerce::is_payment_gateway_configured() returns true. That method instantiates your gateway, asks it for its config class and calls is_configured() inside a try block, so a missing method or a constructor that throws simply hides the gateway. For the settings screen, core passes its gateway list through the tutor_payment_gateways filter, which is how Tutor Pro adds its catalogue; the PayPal entry in core's Settings class shows the expected keys, including name, label, support_subscription and fields.

The gateway and config classes

GatewayBase declares three abstract methods: get_root_dir_name(), get_payment_class() and get_config_class(). Its constructor loads whatever get_autoload_file() returns, falls back to core's bundled vendor autoloader when \Brick\Money is not loaded, and builds $this->payment through PaymentHub::make(). A skeleton for a hypothetical "Acme Pay" gateway, not run on a live site; test on staging first:

namespace AcmePayTutor;

use Tutor\PaymentGateways\GatewayBase;

class AcmeGateway extends GatewayBase {
    public function get_root_dir_name(): string {
        return 'AcmePay';
    }

    public function get_payment_class(): string {
        return \AcmePayTutor\Payments\AcmePayment::class;
    }

    public function get_config_class(): string {
        return AcmeConfig::class;
    }

    public static function get_autoload_file() {
        return ''; // Return a path if the provider SDK has its own Composer autoloader.
    }
}

The config class reads the saved settings with Settings::get_payment_gateway_settings( 'acmepay' ) and overrides the getters that BaseConfig::createConfig() collects: getMode(), getSecretKey(), getPublicKey(), getWebhookSecretKey() and getName() through a $name property. Tutor Stripe also uses core's PaymentUrlsTrait, which supplies getSuccessUrl(), getCancelUrl(), getWebhookUrl() and a get_field_value() helper, so redirects and the webhook URL stay consistent with core. Implement is_configured() to return true only when every required credential is present.

The payment class contract

BasePayment has four abstract methods: setup(), check(), createPayment() and verifyAndCreateOrderData( object $payload ). Two more are expected by GatewayBase if you support them: createRecurringPayment() and createRefund(). make_refund() checks with method_exists() and throws "Refund from payment gateway is not available." when the method is absent.

Tutor callsWhich runs on your payment classStripe add-on behaviour
setup_payment_and_redirect( $data )setData(), then createPayment()Creates a Stripe Checkout Session and redirects to it
verify_webhook_signature( $webhook_data )verifyAndCreateOrderData()Verifies the signature, maps the event to an order status
make_recurring_payment( $order_id )setData(), then createRecurringPayment()Charges the saved payment method off-session
make_refund( $refund_data )setData(), then createRefund()Creates a refund for the order amount

The data passed to setData() for a one-time order comes from CheckoutController::prepare_payment_data(): an object with items, subtotal, total_price, order_id, a currency object, billing_address, customer and related fields. Tutor Stripe overrides setData() to branch on a type property (one-time, recurring or refund) and reshape the data for each call. Carry the Tutor order_id to the provider as metadata, because the webhook has to return it.

Webhooks and the order data you return

Core registers one public REST route for every gateway, tutor/v1/ecommerce-webhook, with the gateway key as a payment_method parameter. The handler packs $_GET, $_POST, $_SERVER and the raw request body into an object and passes it to your verifyAndCreateOrderData(). Because the route itself has no authentication, your method must verify the provider's signature before it trusts anything; Tutor Stripe calls \Stripe\Webhook::constructEvent() and accepts only an allow-list of event types.

Return the object from System::defaultOrderData( 'payment' ) with these properties filled: id (the Tutor order id), payment_status, transaction_id, payment_payload, fees and earnings. When the returned object has an id property, core fires tutor_order_payment_updated, and its handler updates the order and fires tutor_order_payment_status_changed, which drives enrolment and earnings. Return an empty stdClass for events you want to ignore. If you add a redirectUrl property, core redirects with wp_safe_redirect(). Our Stripe pending-order checklist shows what goes wrong when this path fails.

Subscriptions and refunds

Tutor Pro's subscription add-on drives renewals itself. Its SubscriptionController creates the renewal order and calls make_recurring_payment(), which prepares the data with CheckoutController::prepare_recurring_payment_data(). Tutor Stripe does not use Stripe Billing: it saves the payment method at first checkout and creates an off-session PaymentIntent for each renewal. A provider that can only bill through its own subscription objects does not fit this model without extra synchronisation work, so check this before promising subscription support. Mark the gateway with support_subscription only when createRecurringPayment() works.

Refunds started from Tutor's order screen go through OrderController to make_refund(). In Tutor Stripe 1.0.9, refund webhooks from the Stripe Dashboard are verified but not applied to Tutor orders, so refunds should be issued from Tutor.

Packaging, dependencies and upgrade risk

  • Autoloading. Tutor Stripe's Composer map points Ollyo\PaymentHub\ at ../tutor/ecommerce/PaymentGateways/Paypal/src. That couples the add-on to Tutor's folder name and internal layout. A custom gateway that does the same should check on activation that Tutor is active, as Tutor Stripe does on plugins_loaded at priority 100.
  • Pro dependency. Tutor Stripe requires both Tutor and Tutor Pro and reads its field list from TutorPro\Ecommerce\Config. A gateway that registers its own settings fields through tutor_payment_gateways avoids the second dependency, but you then own the settings UI contract.
  • Money handling. Convert amounts to the provider's minor units and handle zero-decimal currencies. Tutor Stripe keeps a list of zero-decimal currencies and per-currency minimum charges in its Helper class.
  • Upgrade testing. GatewayBase and BasePayment are internal framework classes, not a documented public API. Re-test checkout, webhook, renewal and refund on staging after every Tutor or Tutor Pro update.

When a custom gateway is worth building

Build one when your market needs a provider that Tutor's catalogue does not cover, or when finance needs fees and settlement data recorded on Tutor orders. If WooCommerce already supports the provider, compare that route first; our Tutor native e-commerce vs WooCommerce comparison covers the trade-offs. For broader provider design, including idempotent webhooks, see LMS Stripe integration. Step-by-step setup of the gateways Tutor already offers belongs on Tutor LMS Expert.

How we can help

We design and build payment gateway add-ons for Tutor LMS's native checkout, including webhook verification, renewals, refunds and upgrade test plans. See our LMS plugin development service, or contact us with your provider's API documentation.

Frequently asked questions

Can I add a custom payment gateway to Tutor LMS?

Yes, for Tutor's native e-commerce. A gateway plugin provides a class extending Tutor\PaymentGateways\GatewayBase, a config class extending Ollyo\PaymentHub\Core\Payment\BaseConfig and a payment class extending BasePayment, and registers them through the tutor_payment_gateways_with_class and tutor_gateways_with_class filters. With WooCommerce or EDD monetisation, use those platforms' gateway systems instead.

What is Ollyo PaymentHub in Tutor LMS?

It is the payment framework bundled inside Tutor core under ecommerce/PaymentGateways/Paypal/src. Its PaymentHub class builds a gateway's config, injects it into the payment object, runs check() and setup(), and returns the ready payment object that Tutor's GatewayBase calls for checkout, webhooks, renewals and refunds.

What is the Tutor LMS webhook URL for a payment gateway?

Tutor registers one REST route, tutor/v1/ecommerce-webhook, for all gateways, and identifies the gateway by its payment_method parameter. The Stripe add-on builds it from home_url() with payment_method=stripe. The route is public, so each gateway verifies the provider's signature in verifyAndCreateOrderData().

Do Tutor LMS subscriptions use Stripe Billing?

No. In Tutor Stripe 1.0.9, the first checkout saves the payment method, and Tutor Pro's subscription add-on creates each renewal order and calls make_recurring_payment(), which charges the saved method off-session through a PaymentIntent.

Free 30-minute consultation

Not sure where to start? Talk to an LMS engineer.

Tell us what platform you run and what you need. You’ll get honest, practical advice - even if the answer is that you don’t need us.

Sources & references

  1. Tutor LMS plugin (WordPress.org) - WordPress.org
  2. Tutor LMS documentation - Themeum
  3. Stripe webhooks: verify signatures - Stripe
  4. WordPress REST API: adding custom endpoints - WordPress.org
Add as a preferred source on Google

Add All-in-One LMS as a preferred source to see more of our articles in Google’s Top Stories.

Learn more about this topic with AI

Gemini opens with the prompt copied - paste it into the chat to start.

Keep reading

Before you go - get a free LMS audit

Tell us which LMS you use and what is not working. An engineer replies within one business day.

Choose which optional cookies we may use. You can change this at any time from "Cookie preferences" in the footer. Cookie policy · Privacy policy