sol-parts/payum-monobank

Payum gateway for monobank acquiring (plata by mono): hosted checkout, hold payments and signed webhooks

Maintainers

Package info

github.com/sol-parts/payum-monobank

Homepage

pkg:composer/sol-parts/payum-monobank

Transparency log

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v1.0.0 2026-08-18 13:22 UTC

This package is auto-updated.

Last update: 2026-08-18 13:46:52 UTC


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 with paymentType=hold: the funds are locked for up to 9 days and the store settles the payment later.
  • DoCapture (the shared request from sol-parts/payum-contracts, when installed) — settle a held payment via invoice/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 the refundAmount detail, plus optional extRef and fiscal items.
  • Notify — the webhook body is verified against the merchant public key (ECDSA-SHA256, X-Sign header) and bound to the transaction's invoiceId before the payload is applied.
  • Sync — re-fetch the invoice state via invoice/status.
  • GetStatus — maps monobank statuses to Payum ones, including hold (authorized), reversed (refunded) and expired.

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 amount of DoCapture and the refundAmount of Refund.
  • A hold lives 9 days: without invoice/finalize monobank reverses it and returns the money. DoCapture on an already-reversed hold (errCode 1001) is not an error — the action re-syncs and the payment ends up reversed / refunded.
  • failure is not terminal: the invoice stays payable until it expires, so GetStatus deliberately reports such a payment as unknown rather than failed, and the capture flow redirects the customer back to pageUrl for another attempt.
  • Webhook delivery order is not guaranteed. Both the webhook and Sync apply 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/pubkey on every webhook, without persistent caching. When that fetch fails, the gateway answers 503 so monobank redelivers the webhook later; a webhook with an invalid X-Sign, or one about a different invoiceId than the transaction's, is answered 200 and 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.