One connection layer for Drupal. Configure a secret and an endpoint once, and let a small plugin handle the one thing that's actually different about each external system: a payment provider, a Google service, or whatever comes next. A separate, pluggable authentication layer means a connector picks how it authenticates (an API key, a bearer token, OAuth2) instead of reinventing it per provider.
Every integration tends to rebuild the same plumbing from scratch. Connector Hub builds that plumbing once, so a new integration is mostly the one part that's genuinely different.
Each integration invents its own place to store a secret, its own retry logic for a flaky API, its own webhook route with its own signature check, and its own admin screen to configure it. Five integrations, five slightly different versions of the same problem.
A connector endpoint holds the connection: which plugin, which secret (via the Key module, never in configuration), whether it sends, receives, or both. A queue handles delivery and retries. A webhook route handles rate limiting and the path token. The plugin only has to speak the one dialect that system actually uses.
Connector Hub itself stays generic on purpose. Payment was the first domain built on it; authentication is the first primitive pulled back out into its own layer, once a second domain (Google) needed the exact OAuth2 flow a payment adapter's own secret handling never had to worry about.
Four domains build on the same foundation above:
Nothing here is described as finished until it has run inside a real Drupal 11 install, not just read back correctly on the page.
In order, and open to reshuffling if a real project needs a specific provider sooner.
With an explicit choice between its Sessions/Drop-in flow and the lower-level API, made once and documented, not assumed.
Three more Google adapters on the exact same connector_hub_auth OAuth2 primitive — no core or auth-layer changes anticipated, only new submodules.
Three more authentication mechanisms on connector_hub_auth's own roadmap, for whichever provider needs them first.
CRM, ERP and PEPPOL e-invoicing connectors, built the same way: a small plugin on top of the same core, authenticating through whichever connector_hub_auth provider actually fits.
The same four steps apply to any provider this ships an adapter for - only the account and dashboard change. Here's Mollie's version; Stripe's own walkthrough (two secrets instead of one) is in the developer reference.
Free to sign up, test mode works immediately - no business verification needed until live payments. Sign up on mollie.com.
In the Mollie dashboard: Developers › API keys (or API access tokens, depending on your dashboard version). Copy the key starting with test_. Mollie's own guide on API keys.
Create a Key (Configuration › Key) holding that value, then a Connector endpoint (Configuration › Web services › Connector Hub) using the Mollie plugin and that Key.
Register an operation, then call PaymentInitiatorInterface::initiatePayment() with it, the endpoint, and a return URL - redirect the customer to the checkout URL it gives back.
The full developer reference - architecture, code samples, and the reasoning behind it - lives on its own page. Here's the short version plus each module's own README.
Covers the connector endpoint entity, the plugin interface (send(), verifyInboundRequest(), the configuration form hooks), the dispatcher service, and the webhook controller. Includes the exact steps to add a new connector plugin in a separate module.
administer connector endpointsCovers Money, PaymentStatus, RemoteReferences, the PaymentOperation entity, and the four small contracts an adapter implements only where it applies: initiating, reading status, refunding, and supplying customer details. connector_hub_payment_demo is a small, working example built on all of it, worth reading before building a new adapter.
view payment operationsCovers the two pluggable provider systems (AuthenticationProviderInterface for outbound, InboundVerificationProviderInterface for inbound), the five/two shipped mechanisms, the composition-over-inheritance rule a connector follows to use one, and the generic admin connect flow for interactive providers.
administer connector endpoints (reused, no new permission)Covers GoogleConnectorPluginBase (the one place any Google URL is hardcoded), CalendarEventManagerInterface, and how the two shipped submodules — login and Calendar — each compose a connector_hub_auth provider instead of extending anything Google-specific.
administer connector endpoints (reused, no new permission)Covers SlackNotifierInterface::postMessage(), the bespoke timestamp-prefixed HMAC verifyInboundRequest() uses instead of the generic provider, and how a slash command's reply reaches Slack asynchronously through its own response_url rather than the original request.
administer connector endpoints (reused, no new permission)Covers NotifierInterface::notify() and NotificationDispatcher's own "never throws" contract — and why this generalized now rather than speculatively, the same bar connector_hub_auth was held to.
administer connector endpoints (reused, no new permission)Covers TextGeneratorInterface, AiGenerationWorker's queue-based design, the ai_draft bundle and its own field_draft_body, and the direct dependency on connector_hub_notify.
administer connector endpoints (reused, no new permission)Covers SlashCommandToGenerationSubscriber's word-target parse, and why this bridge module ended up smaller than it started — the notify half moved into connector_hub_ai once it turned out to generalize.
administer connector endpoints (reused, no new permission)Both modules are open source under GPL-2.0-or-later. Every change follows the same bar, documented in each module's CONTRIBUTING.md. Each repository also has its own API_STABILITY.md: semantic versioning intent from the first tagged release, which interfaces are covered by it, and the house rule for evolving one without breaking callers.
Each module is tested against a real Drupal 11 site via DDEV, not assumed to work from reading the code.
# inside either module's own directory ddev config --project-type=drupal11 --docroot=web ddev add-on get ddev/ddev-drupal-contrib ddev start && ddev poser && ddev symlink-project # then ddev phpcs && ddev phpstan analyze . && ddev phpunit web/modules/custom