Paying through Unzer
The Unzer driver charges through Unzer's payment API. A charge names either a payment type, the id of a card, a PayPal account or a bank account created with Unzer, or a method that Unzer's hosted payment page offers. On the hosted page the customer enters the card on Unzer's host, so a card number never reaches the application.
Unzer has no subscriptions of its own, and the driver keeps no stored payment methods. A charge without the customer present is refused. A payment on the hosted page is confirmed when the customer comes back, and Unzer's notifications report the changes after that once their address is registered.
Setting it up
Set billing.default to unzer and put the key pair of the Unzer account into BILLING_UNZER_PRIVATE_KEY and
BILLING_UNZER_PUBLIC_KEY. A key beginning s- reaches Unzer's sandbox, one beginning p- the live system.
billing.unzer.methods names the methods the account offers as Unzer's hosted payment page spells them, with card
for cards, and billing.unzer.page sets the name and the style the page shows.
Sending the customer to the hosted page
A charge whose token is a method opens a page for one attempt to pay. Its reference is the page's id, and
clientSecret holds the address to send the customer to:
use Pushery\Billing\Drivers\Unzer\UnzerPaymentRails;
use Pushery\Billing\ValueObjects\ChargeOptions;
use Pushery\Billing\ValueObjects\Money;
$result = app(UnzerPaymentRails::class)->charge(
amount: Money::of(4990, 'EUR'),
token: 'card',
idempotencyKey: $order->number,
options: new ChargeOptions(returnUrl: route('orders.returned', $order)),
);
$order->update(['unzer_page' => $result->reference]);
return redirect()->away((string) $result->clientSecret);
The idempotency key becomes the payment's order id. A second charge under the same key reports the payment an
earlier page made while that payment stands, paid or with its money moving, and otherwise opens a new page: Unzer
asks for a new page for every attempt, and a page lapses after sixty minutes. With captureMode: 'manual' in the
options the page authorizes the amount instead, and UnzerCaptures captures it later.
Confirming the payment on return
Unzer sends the customer back to the return address with the payment's id in the paymentId parameter. A browser can
put any id there, so the return proves nothing on its own. confirmPage() reads the page back from Unzer and takes the
payment only when the page lists it:
use Pushery\Billing\Drivers\Unzer\UnzerPaymentRails;
use Pushery\Billing\ValueObjects\Money;
$result = app(UnzerPaymentRails::class)->confirmPage(
paypageId: $order->unzer_page,
paymentId: (string) $request->query('paymentId'),
amount: Money::of(4990, 'EUR'),
);
A paid payment comes back successful, with Unzer's payment id as its reference, the one a refund names later. A
payment still in flight comes back pending. A payment the page does not list is refused with not_on_page, and a page
without a payment, a lapsed one among them, with no_payment; the next charge then opens a new page.
Receiving Unzer's notifications
Unzer sends notifications only to an address registered for the key pair. php artisan billing:unzer:webhooks
registers the package's webhook address for every change of a payment, and --remove takes the registration away.
Unzer signs no notification, so the driver takes one as a prompt and nothing more. It has to name a payment by an id
of Unzer's shape, and the key pair by the public key in BILLING_UNZER_PUBLIC_KEY where that is set, and
billing.unzer.webhook_senders can limit the addresses it may come from. The payment is then read back from Unzer
with the application's private key, never from the address the notification carries, so a notification about a payment
of another account changes nothing. A completed payment reports PaymentSucceeded, and one canceled before any charge
PaymentFailed. A refund after a charge reports AddonRefunded with the refunded total, and each chargeback Unzer
books reports ChargebackReceived with its amount and its id, s-cbk-…, as disputeReference. The chargebacks count
in the refunded total, as on every driver. Both are read off the payment's transactions, and only what Unzer reports
as successful counts.
A customer who pays on the hosted page and closes the browser never comes back to the return address, so the
application learns the payment from the notification alone. Its PaymentSucceeded names Unzer's payment id as
reference and the idempotency key the charge was started under as orderReference, the key the application
stored the order by before the payment existed.
Payment accounts
In the payments mode each shop brings the key pair of its own Unzer account. UnzerAccounts connects one after
checking the pair with Unzer and disconnects it again; the guide on payment accounts describes both beside the
other providers.