Skip to content

Gateways overview

GatewayNameCheckoutRefundsStatus pollingSaved cardsProvider subscriptionsWebhook setup
Monobank AcquiringmonobankHosted page (url)✓✓✓—none
LiqPayliqpaySigned form → package page✓✓✓—none
WayForPaywayforpayHosted page (url)—✓✓ (always)—none
HutkohutkoHosted page (url)✓✓✓—none
StripestripeHosted Checkout (url)✓✓✓✓register once
PaddlepaddlePaddle.js on your page✓ (with approval)✓—✓register once + dashboard
FakefakeLocal two-button page————none, local/testing only

All of them implement the health check.

use Fomvasss\Billing\Facades\Billing;
Billing::gateways();
// [
// 'monobank' => [
// 'key' => 'monobank',
// 'label' => 'Monobank Acquiring',
// 'currencies' => ['UAH', 'USD', 'EUR'],
// 'credential_fields' => [['name' => 'token', 'type' => 'text', 'secret' => true, 'help' => '...'], ...],
// 'webhook_url' => 'https://example.com/billing/webhooks/monobank',
// 'webhook_requires_dashboard_setup' => false,
// 'capabilities' => ['refunds' => true, 'subscriptions' => false, 'tokenization' => true, 'health' => true],
// ],
// ...
// ]
Billing::gateway('monobank'); // one entry, or null when not registered
MonobankGateway::credentialFields(); // static — no credentials or instance needed

credential_fields entries: name (the config key), type (text/number), secret (mask it in a UI), help (where to get the value; Ukrainian in the built-in drivers). capabilities.subscriptions means provider-managed subscriptions — every gateway with tokenization supports package-managed ones.

A live, side-effect-free probe — “do the credentials work and is the API up right now”:

Billing::health('monobank');
// GatewayHealth { ok: true, message: 'My Shop LLC', latencyMs: 179.2 }
Terminal window
php artisan billing:health # table of every configured health-capable gateway, exit 1 if any is down
php artisan billing:health monobank
GatewayProbe“Up” means
MonobankGET /api/merchant/detailsmerchant name returned
LiqPaystatus of a nonexistent ordererr_code: payment_not_found
WayForPayCHECK_STATUS of a nonexistent orderreasonCode 1127 (order not found)
Hutkostatus/order_id of a nonexistent ordererror_code 1018
StripeGET /v1/balancelivemode: yes/no
PaddleGET /event-typeslive / sandbox
Fake—always up

A probe never throws — a failure (including missing credentials) becomes ok: false with the reason.

Price::$gateway pins a price to one gateway; null makes it generic. resolveChargeAmount() prefers a gateway-specific sibling in an accepted currency, then a generic one — see Money and currencies.

Billing::extend('acmepay', AcmePayGateway::class)
->registerWebhook('acmepay', AcmePaySignatureValidator::class);

See Writing a gateway.