PHPackages                             kommandhub/paystack-sw - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Payment Processing](/categories/payments)
4. /
5. kommandhub/paystack-sw

ActiveShopware-platform-plugin[Payment Processing](/categories/payments)

kommandhub/paystack-sw
======================

Independent, third-party Shopware 6 integration for the Paystack payment gateway: accept secure payments via cards, bank transfers, USSD, and mobile money across Africa. Not affiliated with, endorsed by, or officially connected to Paystack.

0.9.0-beta.2(3w ago)07Apache-2.0PHPCI passing

Since Jul 15Pushed 3w agoCompare

[ Source](https://github.com/KommandHub/KommandhubPaystackSW)[ Packagist](https://packagist.org/packages/kommandhub/paystack-sw)[ Docs](https://github.com/KommandHub/KommandhubPaystackSW)[ RSS](/packages/kommandhub-paystack-sw/feed)WikiDiscussions main Synced yesterday

READMEChangelog (3)Dependencies (14)Versions (5)Used By (0)

Paystack Payment for Shopware 6
===============================

[](#paystack-payment-for-shopware-6)

[![License: Apache 2.0](https://camo.githubusercontent.com/a549a7a30bacba7bfceebdc207a8e86c3f2c02995a2527640dca30048fd2b64e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c6963656e73652d417061636865253230322e302d626c75652e737667)](https://opensource.org/licenses/Apache-2.0)[![Shopware](https://camo.githubusercontent.com/a91c95b028d5774173753b926259e7f9521d5cc522ff950c99cee9d6b2f56f7b/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f53686f70776172652d362e36253230253743253230362e372d626c75652e737667)](https://shopware.com)[![PHP](https://camo.githubusercontent.com/621fdca541f24335b431f1150245e30245c59db9ea5faafd3ba91c224ce4abb8/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e322532422d3737376262342e737667)](https://www.php.net)[![PHPStan](https://camo.githubusercontent.com/1bc07920f0d36e55c17e1d38b1caa132cc605f51a82b388c962870b9a747b898/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230392d627269676874677265656e2e737667)](https://phpstan.org)

 [ ![Kommandhub Logo](src/Resources/config/kommandhub.png) ](https://kommandhub.com)

A production-grade **Shopware 6 payment plugin** that integrates the **[Paystack](https://paystack.com)** payment gateway, enabling merchants across Africa to accept secure online payments through cards, bank transfers, USSD, and mobile money.

Developed by [Kommandhub Limited](https://kommandhub.com).

> **Independent integration.** This is an independent, third-party plugin. It is **not** affiliated with, endorsed by, sponsored by, certified by, or officially supported by Paystack. "Paystack" and the Paystack logo are trademarks of their respective owner and are used here only to identify the payment gateway this plugin connects to. See [Trademarks &amp; Disclaimer](#trademarks--disclaimer).

This document is the technical reference for developers **contributing to** the plugin. If you only want to install and configure it on a live shop, the [Installation](#installation) and [Configuration](#configuration) sections are enough.

---

Table of Contents
-----------------

[](#table-of-contents)

- [Project Overview](#project-overview)
- [Key Features](#key-features)
- [Supported Payment Channels](#supported-payment-channels)
- [Architecture Overview](#architecture-overview)
- [Technology Stack](#technology-stack)
- [Directory Structure](#directory-structure)
- [System Requirements](#system-requirements)
- [Installation](#installation)
- [Local Development Setup](#local-development-setup)
- [Docker &amp; Docker Compose](#docker--docker-compose)
- [Makefile Commands](#makefile-commands)
- [Configuration Options](#configuration-options)
- [Build &amp; Asset Compilation](#build--asset-compilation)
- [Testing](#testing)
- [Code Quality](#code-quality)
- [Data Handling](#data-handling)
- [Logging &amp; Debugging](#logging--debugging)
- [Security Considerations](#security-considerations)
- [Performance Considerations](#performance-considerations)
- [Deployment](#deployment)
- [CI/CD](#cicd)
- [Version Compatibility](#version-compatibility)
- [Troubleshooting](#troubleshooting)
- [Contributing](#contributing)
- [Coding Standards](#coding-standards)
- [Roadmap](#roadmap)
- [License](#license)
- [Trademarks &amp; Disclaimer](#trademarks--disclaimer)
- [Support](#support)

---

Project Overview
----------------

[](#project-overview)

The plugin adds Paystack as a native Shopware 6 payment method. It handles the full payment lifecycle:

1. **Initialize** a Paystack transaction and redirect the customer to Paystack's hosted checkout.
2. **Finalize** the payment on return by verifying the transaction against the Paystack API — matching **status, amount, and currency** before the order is marked paid.
3. **Reconcile** payments asynchronously via signed webhooks (for cases where the customer never returns from the redirect).
4. **Refund** orders (full or partial) from the Administration, guarded by a dedicated permission and a server-side over-refund check.

It also provides customer bank-account verification (via Paystack's account-resolution endpoint) and correct money handling for the currencies Paystack supports, including zero-decimal (e.g. XOF, RWF) and three-decimal (e.g. KWD) currencies.

> The plugin does **not** create currencies or languages in your shop. Amounts are converted correctly for whichever currency an order uses; adding a currency (e.g. XOF) or a language to Shopware remains a normal shop configuration step.

---

Key Features
------------

[](#key-features)

- Native Shopware 6 payment method with Paystack hosted checkout.
- Payment verification that validates **status + amount + currency** (the return reference is attacker-controllable, so all three are checked).
- Asynchronous reconciliation through signed webhooks: `charge.success`, `refund.pending`, `refund.processed`.
- Full and partial refunds from the order detail page, with a **server-side over-refund cap**.
- A dedicated **`paystack.refund`** admin permission, assignable to roles (depends on the order editor permission).
- Customer bank-account verification in the account area.
- Correct amount handling for every currency Paystack supports, including 0-decimal (e.g. XOF, RWF) and 3-decimal (e.g. KWD) currencies — amounts always cross the Paystack boundary in the right minor unit.
- Plugin interface translated into English, German and French (administration + storefront).
- Optional Paystack split payments (subaccount / charges bearer).
- Configurable, level-filtered logging with a sandbox/live mode toggle.

---

Supported Payment Channels
--------------------------

[](#supported-payment-channels)

Availability depends on your Paystack account and configuration:

- Debit &amp; credit cards
- Bank transfers
- USSD
- QR codes
- Mobile money (Ghana, Kenya, and others)

---

Architecture Overview
---------------------

[](#architecture-overview)

The plugin uses a **feature-first** layout that mirrors Shopware's own plugins (for example, SwagPayPal). Each top-level directory under `src/` is a bounded feature; inside it, code is organized into flat, Symfony-idiomatic folders (`Service`, `Subscriber`, `Handler`, `Struct`, `Event`, `Enum`, `Controller`). There is no `Application/Domain/Infrastructure` layering — a top-level module *is* the boundary, and every class has one obvious home.

**Guiding principles**

- Shopware entry points (payment handler, controllers, subscribers) stay thin and delegate to services.
- A change stays inside its feature module; cross-module access goes through a service, not by deep-linking another module's internals.
- New Paystack API calls go through a typed `Client/Resource/` class, never raw HTTP.
- Money is always in **minor units** at the Paystack boundary and converted only through `PaystackCurrencyHelper`.

**Payment flow**

```
Customer selects Paystack
        │
        ▼
PaymentProcessor.initialize()  ──►  Paystack transaction created, reference persisted
        │
        ▼
Redirect to Paystack hosted checkout
        │
        ▼
Customer pays ──► redirect back ──► FinalizeProcessor.verify()
        │                                   (status == success AND amount AND currency match)
        ▼
Order transaction marked "paid"

If the customer never returns, the `charge.success` webhook reconciles the order
using the reference stored at initialize time (idempotent: it no-ops if already paid).

```

**Refund flow**

```
Admin opens the order → Paystack tab → Refund
        │  (client gate: paystack.refund permission + refundable balance)
        ▼
RefundController.refund()  ──►  server gate: _acl paystack.refund, min & max (over-refund) checks
        │
        ▼
Paystack refund created ──► refund.pending / refund.processed webhooks update Shopware refund records

```

---

Technology Stack
----------------

[](#technology-stack)

LayerTechnologyLanguagePHP 8.2+ (8.3 in the dev container)FrameworkShopware 6 (`shopware/core`, `shopware/storefront`), SymfonyAdmin UIVue, Shopware Administration, Meteor Component Library (`mt-*`)Admin buildVite (output committed under `Resources/public/`)StorefrontTwig + vanilla JS plugin (output under `Resources/app/storefront/dist/`)TestingPHPUnit 11Static analysisPHPStan (level 9)Code stylePHP-CS-FixerLocal environmentDocker + Docker Compose (`dockware/shopware`)CIGitHub Actions---

Directory Structure
-------------------

[](#directory-structure)

```
KommandhubPaystackSW/
├── src/
│   ├── KommandhubPaystackSW.php          # Plugin base class (lifecycle hooks)
│   ├── Administration/
│   │   └── Controller/RefundController.php  # Admin refund API endpoint
│   ├── BankVerification/
│   │   ├── Controller/                   # Storefront account-verification endpoints
│   │   └── Service/                      # Bank validation
│   ├── Checkout/
│   │   ├── Payment/
│   │   │   ├── Handler/                  # Shopware payment handler (pay/finalize/refund)
│   │   │   ├── Service/                  # PaymentProcessor, FinalizeProcessor,
│   │   │   │                             #   RefundProcessor, RefundAggregator,
│   │   │   │                             #   Transaction{Verification,Metadata}Processor,
│   │   │   │                             #   PayloadBuilder, OrderTransactionService, …
│   │   │   ├── Struct/                   # DTOs (e.g. PaystackInitializationResponse)
│   │   │   ├── Event/                    # PaymentFinalizedEvent
│   │   │   └── Enum/                     # PaystackTransactionStatus
│   │   └── Cart/                         # CartValidator + Error/
│   ├── Client/                           # Paystack REST client
│   │   ├── PaystackClient.php
│   │   ├── Http/                         # HttpClientInterface + PaystackHttpClient
│   │   └── Resource/                     # One typed class per Paystack endpoint
│   ├── DataAbstractionLayer/             # Order-transaction reader/writer gateways
│   ├── Webhook/
│   │   ├── Controller/                   # Storefront webhook endpoint
│   │   ├── Service/                      # Signature validator, event factory, processor
│   │   ├── Subscriber/                   # ChargeSuccessSubscriber, WebhookSubscriber
│   │   └── Event/                        # WebhookEvent + charge/refund events
│   ├── Setting/Service/Config.php        # Typed access to system configuration
│   ├── Logging/ConfigurableLogger.php    # Level-filtered logger
│   ├── Exception/                        # Domain exceptions
│   ├── Util/                             # PaystackConstants, PaystackCurrencyHelper
│   ├── Installer/                        # Payment method + custom fields installers
│   └── Resources/
│       ├── config/                       # services.yml, routes.yml, config.xml
│       ├── snippet/                      # Storefront snippets
│       ├── views/                        # Twig templates
│       ├── app/administration/           # Vue admin source (src/) + built assets (public/)
│       └── app/storefront/               # Storefront JS source + dist
├── tests/
│   ├── Unit/                             # Mirrors src/, no Shopware kernel
│   └── Integration/                      # Controller/plugin tests
├── .github/workflows/php.yml             # CI pipeline
├── composer.json
├── phpstan.dist.neon
├── phpunit.dist.xml
├── .php-cs-fixer.dist.php
├── docker-compose.yml
├── Makefile
├── CHANGELOG.md                          # English; CHANGELOG_.md for translations
└── CLAUDE.md                             # Contributor conventions (read this too)

```

> Assets under `Resources/public/` and `Resources/app/storefront/dist/` are **generated**. Never hand-edit them — change the source in `Resources/app/**/src/` and rebuild.

---

System Requirements
-------------------

[](#system-requirements)

- **Shopware**: `~6.6.0` or `~6.7.0`
- **PHP**: `8.2+`
- **Composer**: 2.x
- **Paystack account**:
- **For local development**: Docker and Docker Compose
- **For admin/storefront asset builds**: Node.js (provided inside the dev container)

---

Installation
------------

[](#installation)

### Via Composer (recommended)

[](#via-composer-recommended)

```
composer require kommandhub/paystack-sw
bin/console plugin:refresh
bin/console plugin:install --activate KommandhubPaystackSW
bin/console cache:clear
```

### Manual upload

[](#manual-upload)

1. Build a ZIP containing at least `src/` and `composer.json`.
2. In the Administration, go to **Extensions → My Extensions → Upload Extension**.
3. Install and activate **Paystack Payment**.

After installation, assign the **Paystack Payment** method to your sales channel under **Settings → Shop → Payment Methods**.

---

Local Development Setup
-----------------------

[](#local-development-setup)

The repository ships a Docker Compose stack based on [`dockware`](https://dockware.io) that mounts this plugin into a full Shopware install.

```
# 1. Clone the repository
git clone  KommandhubPaystackSW
cd KommandhubPaystackSW

# 2. Start the stack (builds the container and prepares the shop)
make up

# 3. Install and activate the plugin inside the container
make shell
bin/console plugin:refresh
bin/console plugin:install --activate KommandhubPaystackSW
bin/console cache:clear
exit
```

The plugin directory is mounted at `/var/www/html/custom/static-plugins/KommandhubPaystackSW`; `.git/`, `node_modules/`, and `vendor/` are excluded from the mount. Changes to source files on the host are reflected immediately in the container.

Default dockware credentials:

- **Admin**: user `admin`, password `shopware`
- **Database**: user `root`, password `root`, database `shopware`

---

Docker &amp; Docker Compose
---------------------------

[](#docker--docker-compose)

The stack is defined in [`docker-compose.yml`](docker-compose.yml) and built from a small [`Dockerfile`](Dockerfile):

- **Base image**: `dockware/shopware:6.7.8.0`
- **Added tooling**: [`shopware-cli`](https://sw-cli.fos.gg/) — the static binary is copied from the upstream `shopware/shopware-cli:bin` image (latest stable, ~50 MB, multi-arch), so no package manager or cleanup is involved. The build runs `shopware-cli --version` so a broken install fails the image build rather than the first `make validate-plugin`. Pin it for a reproducible build by passing `--build-arg SHOPWARE_CLI_IMAGE=shopware/shopware-cli:bin@sha256:`.
- **Container**: `kommandhub-paystack-plugin`
- **PHP**: 8.3 (`XDEBUG_ENABLED` toggle available)
- **Persistent volume**: `database` (MySQL data)

```
make up        # build + start + prepare
make down      # stop and REMOVE volumes (wipes the database)
make shell     # open a shell in the container
```

> **No host port is published by default.** To reach the Administration from your browser, add a mapping such as `ports: ["80:80"]` to the `shopware` service and reload with `docker compose up -d`. Do **not** use `make restart` for this — it runs `docker compose down -v`, which deletes the database volume and the installed shop.

---

Makefile Commands
-----------------

[](#makefile-commands)

All targets run the underlying tools inside the running container.

CommandDescription`make up`Build, start, and prepare the Shopware container`make down`Stop the container and remove volumes (wipes the DB)`make build`Rebuild the container image`make restart``down` + `up` (wipes the DB)`make shell`Open a bash shell in the container`make plugin-list`List installed plugins`make test`Run PHPUnit. Filter with `make test FILTER="--filter SomeTest"``make test-coverage`Run PHPUnit with a text coverage report`make cs`PHP-CS-Fixer dry run (no changes)`make cs-fix`PHP-CS-Fixer, applying fixes`make analyse`PHPStan static analysis on `src/``make fixture-load`Load test fixtures`make resync`Sync the test config into the shop root`make prepare`Full project preparation (run by `make up`)`make validate-plugin`Validate the plugin with `shopware-cli` (`--full --store-compliance`)`make cli`Run any `shopware-cli` command: `make cli ARGS="extension get-version ."``make changelog`Render `CHANGELOG.md` as the Shopware Store would display it`make zip`Build a distributable plugin zip into `build/``shopware-cli` ships inside the container image (see [Docker &amp; Docker Compose](#docker--docker-compose)), so these run against the same PHP version and installed Shopware as the tests — not whatever is on the host. No local install is required.

**Before committing, run:**

```
make cs-fix && make analyse && make test
```

---

Configuration Options
---------------------

[](#configuration-options)

Configure the plugin under **Extensions → My Extensions → Paystack → Configuration**. Options are stored in Shopware's system configuration under the `KommandhubPaystackSW.config.*` domain and read through `Setting\Service\Config`.

KeyTypePurpose`apiSecretKey`passwordLive secret key (`sk_live_...`)`enableSandbox`boolUse the sandbox/test key instead of live`apiSecretKeySandbox`passwordTest secret key (`sk_test_...`)`enableSplitPayment`boolEnable Paystack split payments`subaccountCode`textSplit payment subaccount code`splitCode`textSplit payment split code`splitPaymentTransactionCharge`intFlat transaction charge for split payments`paystackChargesBearer`selectWho bears fees: Account (merchant) or Subaccount`metaData`multi-selectExtra order/customer data sent to Paystack`collectBankData`boolCollect customer bank data in the account area`showBvnField`boolShow the BVN field`requireBvn`boolMake the BVN field required`refundEnabled`boolAllow refunds from the Administration`minimumRefundAmount`intMinimum refund amount, in minor units`enableDebugging`boolEnable verbose logging`logLevels`multi-selectPSR-3 levels to log when debugging is enabled> Secret keys are stored in Shopware's system configuration, never in code. There is no public key setting — Paystack initialization is server-to-server using the secret key.

---

Build &amp; Asset Compilation
-----------------------------

[](#build--asset-compilation)

PHP has no build step beyond `composer install`. Frontend assets do, and their compiled output is committed to the repository.

**Administration (Vue → Vite)**, output to `Resources/public/administration/`:

```
make shell
./bin/build-administration.sh
```

**Storefront**, output to `Resources/app/storefront/dist/`:

```
make shell
./bin/build-storefront.sh
```

Rebuild the relevant bundle whenever you change source under `Resources/app/administration/src/` or `Resources/app/storefront/src/`, and commit the regenerated assets together with the source. Keeping route names, service IDs, and custom-field keys stable means most PHP changes require **no** asset rebuild.

---

Testing
-------

[](#testing)

Tests live under `tests/` and mirror `src/`. Each behavior change should ship with a test.

```
make test                              # full suite
make test FILTER="--filter RefundControllerTest"
make test-coverage                     # text coverage report
```

- **Unit tests** (`tests/Unit/`) use plain `PHPUnit\Framework\TestCase` with mocks and require no Shopware kernel. These run in CI.
- **Integration tests** (`tests/Integration/`) exercise controllers and the plugin lifecycle. Those tagged `#[Group('kernel')]` need a booted Shopware kernel and database, so they run locally via `make test` rather than in the lightweight CI job.
- **End-to-end**: there is no automated E2E suite yet. The payment, refund and webhook flows are validated manually against a running shop with a Paystack **test** key. Automating this is on the [roadmap](#roadmap).

Pure business logic in the admin (`Resources/app/administration/src/service/refund-calculator.js`) has a companion Jest-style spec (`refund-calculator.spec.js`) for a full Shopware admin test runner.

---

Code Quality
------------

[](#code-quality)

ToolCommandConfigPHPStan (level 9)`make analyse``phpstan.dist.neon`PHP-CS-Fixer`make cs` / `make cs-fix``.php-cs-fixer.dist.php`PHPUnit`make test``phpunit.dist.xml`CI enforces PHP lint, PHPStan, code style, unit + mockable integration tests, and a 100% line-coverage threshold. Kernel-dependent tests are excluded from CI.

---

Data Handling
-------------

[](#data-handling)

The plugin ships **no schema migrations** — it does not alter the database schema. All setup is performed through Shopware's plugin lifecycle by dedicated installers:

- **Payment method**: created and kept in sync by `Installer\PaymentMethodInstaller`.
- **Custom fields** (Paystack reference, amount, currency, fee, etc.): created by `Installer\CustomFieldsInstaller` during install/update.

These run on `install()`/`update()` and are reverted appropriately on uninstall (custom fields are removed only when the user does not keep plugin data).

> The plugin's `update()` lifecycle hook re-runs the installers, which migrates the stored payment-method `handlerIdentifier` if the handler class moves between versions. Without this, a plugin **update** (as opposed to a fresh install) would leave a dangling handler identifier and break checkout.

---

Logging &amp; Debugging
-----------------------

[](#logging--debugging)

Logging goes through `Logging\ConfigurableLogger`, wired to the `paystack_channel` Monolog channel (writes to `var/log/`).

- Set `enableDebugging` and pick `logLevels` to control verbose output.
- **Error, critical, alert, and emergency messages are always written**, regardless of the debugging toggle, so production keeps a trail of failures (webhook signature rejections, verification/refund errors).
- Enable Xdebug in the container by setting `XDEBUG_ENABLED=1` in `docker-compose.yml` and restarting.

---

Security Considerations
-----------------------

[](#security-considerations)

- **Webhook authenticity**: `WebhookSignatureValidator` verifies the `x-paystack-signature` HMAC over the raw request body using `hash_equals` (timing-safe) and rejects missing signatures or a missing secret.
- **Payment verification**: an order is marked paid only when the verified transaction matches **status AND amount AND currency**. The return `reference` comes from an attacker-controllable callback, so it is never trusted on its own.
- **Refund authorization**: the refund endpoint requires the dedicated `paystack.refund` privilege (route `_acl`), and the admin action is gated by the same permission.
- **Over-refund protection**: the server recomputes the refundable balance (captures/transaction total minus completed and in-progress refunds) and rejects amounts above it and below the configured minimum. The client-side bound is a UX aid only.
- **Secrets**: API keys live in Shopware's system configuration, not in the codebase or in URLs.
- **Money handling**: amounts cross the Paystack boundary in minor units via `PaystackCurrencyHelper`, which knows per-currency decimals — never multiply by 100 inline.

---

Performance Considerations
--------------------------

[](#performance-considerations)

- Order/transaction reads use targeted DAL criteria with only the associations they need.
- The admin detail view guards against concurrent capture/refund loads and loads plugin configuration reactively rather than on a fixed lifecycle tick.
- Refund math is a pure, memoizable computation isolated in `refund-calculator.js`.

---

Deployment
----------

[](#deployment)

1. Ship the plugin via Composer (`composer require kommandhub/paystack-sw`) or an Administration upload.
2. Run: ```
    bin/console plugin:refresh
    bin/console plugin:update KommandhubPaystackSW   # migrates handler identifier + custom fields
    bin/console cache:clear
    ```
3. Ensure compiled Administration and Storefront assets are built and committed as part of the release.
4. Configure live secret keys and disable sandbox mode.
5. Grant the **Paystack → Process Paystack refunds** permission to the roles that should be able to issue refunds (the built-in admin role already has all privileges).

Validate a release build for the Shopware Store from inside the container, where `shopware-cli` runs against the installed Shopware and full vendor tree:

```
make validate-plugin
# equivalently: make cli ARGS="extension validate . --full --store-compliance"
```

Running the same command against a host-only `shopware-cli` reports false positives (see the PHPStan note under [Troubleshooting](#troubleshooting)) — the container has the dependencies it needs to resolve Shopware's classes.

---

CI/CD
-----

[](#cicd)

GitHub Actions (`.github/workflows/php.yml`) runs on pushes to `main`/`develop` and on pull requests:

1. Validate `composer.json`.
2. Install dependencies.
3. Lint all PHP files.
4. PHPStan (level 9).
5. PHP-CS-Fixer (dry run).
6. PHPUnit unit tests with clover coverage.
7. Enforce a minimum coverage threshold (85%) via `coverage-check`.

Integration tests are excluded from this job because they need a booted Shopware kernel; run them locally with `make test`.

---

Version Compatibility
---------------------

[](#version-compatibility)

PluginShopwarePHP`0.9.0-beta.x`6.6 and 6.78.2+A single plugin release supports both Shopware 6.6 and 6.7 (`shopware/core: ~6.6.0 || ~6.7.0`).

> **Pre-1.0 status:** the plugin is on a `0.x` version while it completes sandbox/staging validation (see [Roadmap](#roadmap)). Namespaces and the public API may still change before `1.0.0`. Once testing is complete and all critical issues are resolved, this will be promoted to `1.0.0` and submitted to the Shopware Store.

---

Troubleshooting
---------------

[](#troubleshooting)

**Order status not updating after payment**

- Confirm the webhook endpoint is reachable from Paystack and the secret key matches the mode (test vs live).
- Check `var/log/` for verification or signature errors.

**Plugin not visible in the Administration**

```
bin/console plugin:refresh
```

**Stale Administration UI or DI errors after changes**

```
bin/console cache:clear
```

**Refund action not shown**

- Ensure `refundEnabled` is on, the role has the `paystack.refund` permission, and the transaction still has a refundable balance.

**PHPStan can't find `Shopware\Storefront\...` during `shopware-cli` validation**

- `shopware/storefront` must be declared in `require` (it is). Do not point `scanDirectories` at the host's `vendor/` — let Composer install and autoload it.

---

Contributing
------------

[](#contributing)

1. Create a feature branch off `develop`.
2. Keep changes inside the relevant feature module; reach across modules through services.
3. Add or update tests alongside behavior changes (mirror the `src/` path under `tests/`).
4. Rebuild admin/storefront assets if you touched their source, and commit the output.
5. Run the full local gate before opening a PR: ```
    make cs-fix && make analyse && make test
    ```
6. Use [Conventional Commits](https://www.conventionalcommits.org/) for commit messages (`feat:`, `fix:`, `refactor:`, `test:`, …).
7. Open a pull request against `develop`.

Please also read [`CLAUDE.md`](CLAUDE.md) for the module boundaries and project-specific conventions.

---

Coding Standards
----------------

[](#coding-standards)

- **PHP style**: PSR-12, enforced by PHP-CS-Fixer (`.php-cs-fixer.dist.php`).
- **Static analysis**: PHPStan level 9 must pass with no new errors.
- **Architecture**: feature-first modules; one obvious home per class; thin Shopware entry points delegating to services.
- **Paystack API**: add new calls as typed classes under `Client/Resource/`, never as raw HTTP.
- **Money**: always convert through `Util\PaystackCurrencyHelper`; amounts are minor units at the Paystack boundary.
- **Custom-field keys**: defined only in `Util\PaystackConstants` (`paystack_reference` is the webhook lookup key).
- **Dependency injection**: services are autowired via the `../../*` glob in `services.yml`. Symfony does not auto-alias an interface to its single implementation — when you add a constructor-injected `*Interface`, add an explicit `alias:` entry.

---

Roadmap
-------

[](#roadmap)

- Complete the migration of Administration components to the Meteor Component Library (`sw-*` → `mt-*`), including data grids and modals.
- Make the storefront bank-verification feature optional for headless setups (decouple from `StorefrontController`).
- Trim unused Paystack API resource classes to the endpoints the plugin actually uses.
- Add automated end-to-end coverage. Planned in layers, cheapest first:
    1. **Paystack sandbox contract tests** — call the real API with an `sk_test_` key to prove the client matches Paystack's contract and that amounts survive the round trip in minor units.
    2. **Webhook endpoint tests** — POST signed/unsigned payloads over HTTP (Paystack signs with HMAC-SHA512 of the raw body using the secret key, in `x-paystack-signature`).
    3. **Browser tests** — storefront checkout through Paystack's hosted page and the Administration refund flow. Notes for whoever picks this up: gate the suite behind an env var so it skips by default, refuse to run against a live key, exclude it from CI, and remember that real webhook delivery needs a public tunnel **and** the tunnel hostname registered as a Shopware sales-channel domain (otherwise Shopware answers `400` before the controller runs).

---

License
-------

[](#license)

Licensed under the **Apache License 2.0**. See [LICENSE](LICENSE) and [NOTICE](NOTICE) for details.

Apache-2.0 was chosen over a simpler permissive licence for its explicit patent grant, its explicit reservation of trademark rights (§6), and the `NOTICE` mechanism that carries attribution downstream into forks. The licence covers this plugin's **own source code only**. It grants **no rights** in the KommandHub name or logo (see [TRADEMARKS.md](TRADEMARKS.md)), nor in Paystack's trademarks, logos, or services (see [Trademarks &amp; Disclaimer](#trademarks--disclaimer)).

---

Trademarks &amp; Disclaimer
---------------------------

[](#trademarks--disclaimer)

This plugin is an **independent, third-party integration** developed and maintained by [Kommandhub Limited](https://kommandhub.com). It is **not** affiliated with, endorsed by, sponsored by, certified by, or officially supported by Paystack or any of its affiliates.

"Paystack", the Paystack logo, and any related names, marks, and logos are trademarks of their respective owner. "Shopware" is a registered trademark of shopware AG. All other trademarks referenced in this project are the property of their respective owners. These marks are used in this project solely for **nominative purposes** — to identify the third-party payment gateway and the platform that this plugin integrates with — and their use does not imply any endorsement, partnership, or affiliation.

Use of the Paystack payment gateway is subject to Paystack's own terms of service and agreements, which are between the merchant and Paystack. This plugin merely provides a technical integration and makes no warranty regarding Paystack's services. To use it you must hold your own valid Paystack account and API credentials.

**KommandHub's own marks** — the "KommandHub" name and logo — are trademarks of Kommandhub Limited. The open-source licence covers the code, not the brand: a fork must be **rebranded** before redistribution. The full policy is in [TRADEMARKS.md](TRADEMARKS.md).

---

Support
-------

[](#support)

- Email: [info@kommandhub.com](mailto:admin@kommandhub.com)
- Website:
- Support:

###  Health Score

33

—

LowBetter than 72% of packages

Maintenance95

Actively maintained with recent releases

Popularity5

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity22

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~60 days

Total

3

Last Release

21d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/0f1debdb2d793fd382ffc606ad8ed6433c9e8b70a9eda51a58227625a2ba412b?d=identicon)[kommandhub](/maintainers/kommandhub)

---

Top Contributors

[![KommandHub](https://avatars.githubusercontent.com/u/225087266?v=4)](https://github.com/KommandHub "KommandHub (22 commits)")

---

Tags

africabank-transfercheckoutecommerceghanamobile-moneynigeriapayment-gatewaypayment-integrationpaymentspaystackrefundshopwareshopware-paymentshopware6-pluginussdwebhookshopwarepaymentwebhookecommerceNigeriacheckoutpayment gatewayrefundmobile-moneypaystackussdafricabank transfershopware6shopware-pluginshopware-payment

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/kommandhub-paystack-sw/health.svg)

```
[![Health](https://phpackages.com/badges/kommandhub-paystack-sw/health.svg)](https://phpackages.com/packages/kommandhub-paystack-sw)
```

###  Alternatives

[adyen/adyen-shopware6

Official Shopware 6 Plugin to connect to Payment Service Provider Adyen

25119.6k](/packages/adyen-adyen-shopware6)[shopware/production

176216.5k](/packages/shopware-production)[postfinancecheckout/shopware-6

PostFinanceCheckout integration for Shopware 6

1010.9k](/packages/postfinancecheckout-shopware-6)[kiener/mollie-payments-plugin

Mollie Payments

6767.7k](/packages/kiener-mollie-payments-plugin)[unzerdev/shopware6

Unzer payment integration for Shopware 6

1235.9k](/packages/unzerdev-shopware6)[payone-gmbh/shopware-6

PAYONE Payment Plugin

2182.8k](/packages/payone-gmbh-shopware-6)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
