setono / sylius-quickpay-plugin
Quickpay payment plugin for Sylius
Package info
github.com/Setono/SyliusQuickpayPlugin
Type:sylius-plugin
pkg:composer/setono/sylius-quickpay-plugin
Fund package maintenance!
Requires
- php: >=8.1
- ext-json: *
- ext-mbstring: *
- doctrine/collections: ^1.6
- doctrine/orm: ^2.7
- fakerphp/faker: ^1.21
- payum/payum: ^1.6
- setono/payum-quickpay: ^1.3
- symfony/config: ^5.4 || ^6.0
- symfony/dependency-injection: ^5.4 || ^6.0
- symfony/form: ^5.4 || ^6.0
- symfony/http-foundation: ^5.4 || ^6.0
- symfony/http-kernel: ^5.4 || ^6.0
- symfony/intl: ^5.4 || ^6.0
- symfony/validator: ^5.4 || ^6.0
- viison/address-splitter: ^0.3.4
- webmozart/assert: ^1.11
- winzou/state-machine: ^0.3 || ^0.4
Requires (Dev)
- api-platform/core: ^2.7
- behat/behat: ^3.12
- lexik/jwt-authentication-bundle: ^2.16
- matthiasnoback/symfony-config-test: ^4.3
- matthiasnoback/symfony-dependency-injection-test: ^4.3
- phpspec/phpspec: ^7.3
- phpunit/phpunit: ^9.5
- psalm/plugin-phpunit: ^0.18
- psalm/plugin-symfony: ^5.0
- setono/code-quality-pack: ^2.4
- sylius/sylius: ~1.12.3
- symfony/debug-bundle: ^5.4 || ^6.0
- symfony/dotenv: ^5.4 || ^6.0
- symfony/property-info: ^5.4 || ^6.0
- symfony/serializer: ^5.4 || ^6.0
- symfony/web-profiler-bundle: ^5.4 || ^6.0
- symfony/webpack-encore-bundle: ^1.16
This package is auto-updated.
Last update: 2026-08-10 14:16:29 UTC
README
Adds Quickpay as a payment gateway to your Sylius store. The plugin integrates the
setono/payum-quickpay Payum gateway into Sylius' checkout,
state machine, and admin.
Requirements
- PHP 8.1 or higher
- Sylius 1.x on Symfony ^6.4 (tested against Sylius 1.14)
- PSR-17 factories discoverable by
php-http/discovery(e.g.nyholm/psr7) — the plugin itself bringssymfony/http-clientas its PSR-18 client
Installation
1. Install the plugin
The plugin builds on setono/payum-quickpay 2.x, which is still in pre-release, so your project
must allow the pre-release versions explicitly:
composer require setono/sylius-quickpay-plugin:^2.0@alpha setono/payum-quickpay:^2.0@alpha setono/quickpay-php-sdk:^1.0@beta
If your project does not already provide PSR-17 factories:
composer require nyholm/psr7
2. Register the bundle
<?php # config/bundles.php return [ // ... Setono\SyliusQuickpayPlugin\SetonoSyliusQuickpayPlugin::class => ['all' => true], ];
3. Configure the plugin (optional)
The state machine callback that captures, refunds, and cancels Quickpay payments when the corresponding Sylius payment transitions are applied (see How it works) is registered automatically. Each operation can be turned off individually:
# config/packages/setono_sylius_quickpay.yaml setono_sylius_quickpay: operations: capture: true # forward the payment's complete transition to Quickpay as a capture refund: true # forward the refund transition to Quickpay cancel: true # forward the cancel transition to Quickpay
The plugin hooks into both state machine adapters supported by Sylius 1.14 — a winzou_state_machine
callback (the default adapter) and a Symfony workflow event subscriber — so the operations are forwarded to
Quickpay no matter which adapter your application runs the sylius_payment graph on.
4. Import the routes
# config/routes/setono_sylius_quickpay.yaml setono_sylius_quickpay: resource: "@SetonoSyliusQuickpayPlugin/Resources/config/routes.yaml"
This registers the callback endpoint (POST /payment/quickpay/notify) that Quickpay's servers use to notify your
store about payment state changes.
5. Import fixtures (optional, development only)
# config/packages/setono_sylius_quickpay.yaml imports: - { resource: "@SetonoSyliusQuickpayPlugin/Resources/config/app/fixtures.yaml" }
The fixtures create a Quickpay credit card payment method and matching channels. They read the gateway credentials from these environment variables:
QUICKPAY_API_KEY= QUICKPAY_PRIVATE_KEY= QUICKPAY_AGREEMENT_ID= QUICKPAY_ORDER_PREFIX=qp_
Configuration
Create a new payment method of type Quickpay in the admin panel (Configuration → Payment methods) and fill out the gateway configuration:
| Field | Description |
|---|---|
| Api key | The API key of the API user in your Quickpay manager (Settings → Users) |
| Private key | The private key of your merchant account (Settings → Integration) |
| Agreement id | (optional) The agreement id used for the payment window |
| Order prefix | Prepended to order numbers sent to Quickpay as the order_id — must be unique per project and environment sharing the same Quickpay account (see Troubleshooting), and 11 characters or less |
| Payment methods | Which payment methods the Quickpay payment window offers, e.g. creditcard or mobilepay — see the Quickpay documentation |
| Auto capture | Capture the payment automatically right after authorization — useful for digital products |
| Synchronized operations | Run capture, refund and cancel synchronously instead of relying on the Quickpay callback |
| Branding id | (optional) The payment window branding to use |
When you save the payment method, the plugin verifies the API key against Quickpay's API (a lightweight ping) and rejects the form if Quickpay rejects the key — a typo'd key is caught immediately instead of by the first customer whose checkout fails. If Quickpay cannot be reached, the check is skipped so an outage never blocks saving.
How it works
- During checkout the customer is redirected to the Quickpay payment window through a payment link. The payment is authorized, not captured (unless Auto capture is enabled).
- Quickpay notifies your store of every payment change on the callback endpoint. The callback's
Quickpay-Checksum-SHA256header is validated against your private key before the payment details are updated. - When you complete, refund, or cancel a payment in the Sylius admin, the plugin performs the matching capture, refund, or cancel operation against Quickpay. A failed cancel at Quickpay (e.g. the customer never completed checkout, so there is nothing to cancel) is logged but does not block cancelling the order.
- A refund targets Quickpay's balance (what is still captured) rather than the original amount — so a payment
that was partially refunded directly in the Quickpay manager refunds only the remainder instead of failing. The
balance is also persisted into the payment details on every status check and callback. An explicit
refund_amount/capture_amountin the payment details is passed through to Quickpay untouched for programmatic partial operations; note that Sylius' payment state machine still treats the payment as a whole — therefundtransition can only be applied once.
Operation history in the admin
Each Quickpay payment on the admin order view shows its live operation history — every authorize/capture/refund/cancel with amount, Quickpay status code and message, and timestamp, plus the captured balance and a test-mode badge. The data is fetched from Quickpay after the page has rendered, so the order page is never delayed by a slow gateway; if Quickpay cannot be reached, the panel shows an inline notice with a retry link. Nothing is stored — the panel reflects what Quickpay reports right now.
Reconciling missed callbacks
The Quickpay callback is normally the only way your store learns about a payment state change. If a callback never arrives — misconfigured callback URL on the Quickpay agreement, store unreachable while Quickpay retried — the payment stays stuck in a non-final state and the order never completes. The plugin ships a reconciliation command that closes this gap by polling Quickpay directly:
bin/console setono:sylius-quickpay:reconcile-payments # last 7 days, max 100 payments bin/console setono:sylius-quickpay:reconcile-payments --since="12 hours" --limit=50 bin/console setono:sylius-quickpay:reconcile-payments --dry-run # report only, change nothing
For each stuck payment it fetches the current status from Quickpay and applies the matching payment transition — the same one the callback would have triggered. A callback racing the command is harmless: transitions are guarded and the resulting Quickpay operations re-check the remote status first.
Scheduling is your application's choice; a cron entry along these lines is plenty:
*/30 * * * * /usr/bin/php /path/to/shop/bin/console setono:sylius-quickpay:reconcile-payments >> /var/log/quickpay-reconcile.log 2>&1
The command exits non-zero when any payment could not be checked, so cron mail or your monitoring will surface persistent problems.
Testing
composer phpunit # unit tests composer analyse # static analysis (PHPStan) composer check-style # coding standards
For manual testing, use the credit card numbers from the Quickpay test data.
Upgrading from 1.x
See UPGRADE-2.0.md for the full list of changes an upgrading store has to make — gateway configuration keys, removed imports, renamed routes and classes, the Klarna removal, and the behavioral changes around refunds and callbacks.
Troubleshooting
-
Not authorized: Not authorized to PUT /payments/:id/linkat/payment/authorize/...url:You should check at
https://manage.quickpay.net/account/{your merchant id}/settings/usersthatSystem users>API User>User permissions>Create or update payment linkhavePUTcheckbox checked. Also checkQUICKPAY_API_KEYandQUICKPAY_AGREEMENT_IDis filled withAPI User's api key and agreement id rather thanPayment Window's. -
Validation error: order_id already exists on another paymentMake sure you changed the Order prefix of your Quickpay payment method to some unique string like
qp_<projectname>_<date>_(whendateshould be updated to actual every time you recreate dev database) whenever you:- Recreating your database on dev environment and your order IDs become same as they was before
- Use
SetonoSyliusQuickpayPluginat two different projects but with same Quickpay (developer) account credentials
-
Validation error: order_id must have length between 4 and 20You should cut the Order prefix of your Quickpay payment method to 11 chars or less.