sol-parts / payum-monobank
Payum gateway for monobank acquiring (plata by mono): hosted checkout, hold payments and signed webhooks
Requires
- php: >=8.2
- ext-json: *
- ext-mbstring: *
- ext-openssl: *
- payum/core: ^1.7
- php-http/discovery: ^1.14
- psr/http-factory: ^1.0
- psr/http-message: ^1.1|^2.0
- psr/log: ^1.1|^2.0|^3.0
Requires (Dev)
- nyholm/psr7: ^1.8
- phpunit/phpunit: ^11.5
Suggests
- sol-parts/payum-contracts: Dispatch the shared DoCapture request to settle (finalize) held payments
README
Provides monobank acquiring (plata by mono) integration for Payum: hosted checkout with instant debit or two-stage hold payments, refunds and ECDSA-signed webhooks.
Supported operations:
Capture— create an invoice (invoice/create) and redirect the customer to the monobank payment page (pageUrl).Authorize— same flow withpaymentType=hold: the funds are locked for up to 9 days and the store settles the payment later.DoCapture(the shared request fromsol-parts/payum-contracts, when installed) — settle a held payment viainvoice/finalize, full or partial amount.Cancel— invalidate a not-yet-paid invoice (invoice/remove); payment by that invoice becomes impossible.Refund— refund of a paid invoice (invoice/cancel): the full paid amount by default, a partial one via therefundAmountdetail, plus optionalextRefand fiscalitems.Notify— the webhook body is verified against the merchant public key (ECDSA-SHA256,X-Signheader) and bound to the transaction'sinvoiceIdbefore the payload is applied.Sync— re-fetch the invoice state viainvoice/status.GetStatus— maps monobank statuses to Payum ones, includinghold(authorized),reversed(refunded) andexpired.
Payment flow
sequenceDiagram
autonumber
actor C as Customer
participant S as Store
participant M as monobank
C->>S: Places an order
S->>M: invoice/create (amount, basket, webHookUrl)
M-->>S: invoiceId + pageUrl
S-->>C: Redirect to pageUrl
C->>M: Pays (card, Apple/Google Pay)
M-->>S: Returns the customer to redirectUrl
M->>S: Webhook (X-Sign, invoice snapshot)
S->>S: Verify X-Sign against the merchant pubkey
S-->>C: Order result page
Note over S,M: An unverifiable webhook never touches the payment.<br/>The state can also be re-fetched via invoice/status.
Loading
Authorize creates a hold payment: the money is locked instead of charged,
and monobank auto-reverses the hold after 9 days unless it is finalized:
sequenceDiagram
autonumber
actor C as Customer
participant S as Store
participant M as monobank
C->>M: Confirms the hold payment
M->>S: Invoice status hold — authorized
Note over S: Goods shipped, or the order is dropped
S->>M: DoCapture — invoice/finalize, or Refund — invoice/cancel
M-->>S: success or reversed
Loading
A failed payment attempt (3-D Secure decline, timeout) does not kill the
invoice: monobank allows retries by the same invoiceId, so the gateway keeps
such a payment pending and sends the returning customer back to pageUrl
until the invoice expires.
Installation
composer require sol-parts/payum-monobank
Usage with PayumBuilder
use Payum\Core\GatewayFactoryInterface; use Payum\Core\PayumBuilder; use SolParts\PayumMonobank\MonobankGatewayFactory; $payum = (new PayumBuilder()) ->addGatewayFactory('monobank', static function (array $config, GatewayFactoryInterface $coreGatewayFactory) { return new MonobankGatewayFactory($config, $coreGatewayFactory); }) ->addGateway('monobank', [ 'factory' => 'monobank', 'x-token' => 'your-merchant-token', ]) ->getPayum();
Usage with Symfony PayumBundle
Register the gateway factory:
# config/services.yaml services: app.monobank_gateway_factory: class: Payum\Core\Bridge\Symfony\Builder\GatewayFactoryBuilder arguments: [SolParts\PayumMonobank\MonobankGatewayFactory] tags: - { name: payum.gateway_factory_builder, factory: monobank }
Configure a gateway:
# config/packages/payum.yaml payum: gateways: monobank: factory: monobank x-token: '%env(MONOBANK_X_TOKEN)%'
Options
| Option | Required | Description |
|---|---|---|
x-token |
yes | Merchant token from the monobank acquiring dashboard, sent as the X-Token header on every API call. |
Payment details
ConvertPaymentAction fills amount (minor units — kopecks), ccy (numeric
ISO 4217) and merchantPaymInfo with reference (the payment number, always
cast to string — monobank rejects a numeric one with
INVALID_MERCHANT_PAYM_INFO) and destination.
The gateway itself defaults validity to 24 hours, attaches redirectUrl to
the long-lived after-URL token and webHookUrl to a notify token, so both
survive repeated visits.
A basketOrder supplied by the host application is validated the way
monobank does — Σ(sum × qty) must equal amount, where sum is the price
of a single unit. A basket whose lines carry the line total instead
(Σ(sum) === amount) is transparently rebuilt into unit prices, splitting a
non-divisible remainder across quantity rows; a basket matching neither
formula is passed through untouched.
Caveats
- All amounts are in minor units (kopecks), including the partial
amountofDoCaptureand therefundAmountofRefund. - A hold lives 9 days: without
invoice/finalizemonobank reverses it and returns the money.DoCaptureon an already-reversed hold (errCode1001) is not an error — the action re-syncs and the payment ends upreversed/ refunded. failureis not terminal: the invoice stays payable until it expires, soGetStatusdeliberately reports such a payment as unknown rather than failed, and the capture flow redirects the customer back topageUrlfor another attempt.- Webhook delivery order is not guaranteed. Both the webhook and
Syncapply a snapshot only if it is not older (modifiedDate) and does not roll a mature status (hold,success,reversed,expired) back to a pending one. - The merchant public key is fetched from
api/merchant/pubkeyon every webhook, without persistent caching. When that fetch fails, the gateway answers503so monobank redelivers the webhook later; a webhook with an invalidX-Sign, or one about a differentinvoiceIdthan the transaction's, is answered200and ignored. - Error responses are reported with the HTTP status code and a truncated body snippet — monobank answers with HTML, not JSON, on throttling (429) and balancer errors (5xx).
License
Released under the MIT License.