Payment

Process payments through multiple methods (cash register, QR code, pay by link) with a flexible, event-driven widget.

For installation instructions, see Getting Started with Unify Widgets.

Basic Implementation

<unify-payment-widget
  api-key="your-api-key"
></unify-payment-widget>
const widget = document.querySelector('unify-payment-widget');

// Set the order object (format defined by the Unify API)
widget.order = { /* order data */ };

widget.addEventListener('payment-success', (event) => {
  console.log('Payment complete via:', event.detail.method);
});

Component Attributes

AttributeTypeRequiredDescription
api-keyStringYesAPI key for Unify requests
demoBooleanNoEnable demo mode for testing
linkStringOnly for qrcode / paybylinkPayment link to encode in the QR code / share via the "Pay by Link" button. Unify does not process the payment itself for these two methods — the integrator (ecommerce / StoreApp) is responsible for generating this link and handling the payment flow behind it

Component Properties

PropertyTypeRequiredDescription
configObjectNoConfiguration object (see Config Options)
orderObjectYesOrder data to process. Format is defined by the Unify API — set this before calling selectPaymentMethod()

Read-only state

These properties are reflected as HTML attributes and can be observed via JS or used in CSS selectors:

Property / AttributeValuesDescription
paymentMethod'', 'cash-register', 'qrcode', 'paybylink'Currently active payment method
paymentState'idle', 'sending', 'success', 'error'Current payment processing state
/* Example: style the widget based on state */
unify-payment-widget[payment-state="success"] { ... }

Methods

selectPaymentMethod(method)

Programmatically select and process a payment method.

widget.order = { /* order data */ };
await widget.selectPaymentMethod('cash-register');

Parameters:

  • method (String): 'cash-register', 'qrcode' or 'paybylink'

Returns: Promise — resolves when processing completes, rejects on error.

resetPayment()

Reset the widget to its initial (idle) state.

widget.resetPayment();

Config Options

document.querySelector('unify-payment-widget').config = {
  enabledPaymentMethods: ['cash-register', 'qrcode', 'paybylink'],
  cashRegisterPaymentMethodName: 'Pay at Store',
};

Payment Methods & Labels

OptionDefaultDescription
enabledPaymentMethods['cash-register', 'qrcode']Array of enabled payment methods. 'paybylink' must be explicitly added — it's not enabled by default
cashRegisterPaymentMethodName"Pay at Cash Register"Label for cash register option
qrcodePaymentMethodName"Pay with QR Code"Label for QR code option
paybylinkPaymentMethodName"Pay by Link"Label for the pay by link option
payAtCashRegisterSuccessText"Proceed to pay at your cash register."Text shown after cash register selection

QR Code

The QR code is generated entirely client-side (no network call, no external image/QR service) via qr-code-styling, rendered onto an internal <canvas> (used instead of the library's SVG output, which has a known bug with logos).

document.querySelector('unify-payment-widget').config = {
  qrCodeModuleShape: 'rounded',
  qrCodeMargin: 20,
};
OptionDefaultDescription
qrCodeErrorCorrectionLevel'M' (or 'H' automatically when qrCodeLogoUrl is set)Error correction level: 'L' (~7%), 'M' (~15%), 'Q' (~25%), 'H' (~30%). Higher levels tolerate more visual obstruction (e.g. a center logo) at the cost of a denser code
qrCodeModuleShape'square'Shape of the QR modules (and, to match, the 3 finder pattern "eyes"): 'square', 'rounded' or 'dot'
qrCodeMargin40Quiet zone size around the code, in pixels at the library's internal 1000×1000 render size (scales with the code regardless of the module count, which varies with the link's length and error correction level)
qrCodeLogoUrlundefinedURL (or data URI) of a logo image rendered at the center of the code. When set, the modules underneath are excavated automatically
qrCodeLogoSizeRatio0.2Logo size as a fraction of the code's width (0-0.3 recommended to keep the code scannable)

Pay By Link

The widget always offers a "Send by SMS" and a "Send by Email" button — it doesn't send anything itself, it only reports the customer's choice via payment-link-channel-selected (see Events) for the integrator to act on.

document.querySelector('unify-payment-widget').config = {
  paybylinkSmsButtonLabel: 'Text me the link',
};
OptionDefaultDescription
paybylinkSmsButtonLabel"Send by SMS"Label of the "Send by SMS" button
paybylinkEmailButtonLabel"Send by Email"Label of the "Send by Email" button

Error Handling

OptionDefaultDescription
defaultErrorMessage"An error occurred during payment processing."Fallback error message
showErrorDetailsfalseShow detailed error information when available

Styling

CSS Custom Properties (recommended)

All visual tokens (colors, sizes, spacing, fonts) are exposed as CSS custom properties prefixed with --unify-. This is the stable styling API.

Set them on the widget element or any ancestor:

unify-payment-widget {
  --unify-payment-method-border: #333;
  --unify-payment-method-bg: white;
  --unify-payment-method-color: black;
  --unify-payment-method-option-width: 117px;
  --unify-payment-method-option-height: 100px;
  --unify-pay-button-min-height: 400px;
  --unify-pay-button-border: black;
  --unify-pay-button-bg: transparent;
  --unify-pay-button-color: black;
  --unify-paybylink-button-bg: black;
  --unify-paybylink-button-color: white;
  --unify-paybylink-button-border-width: 0px;
  --unify-paybylink-button-border-color: transparent;
  --unify-paybylink-button-radius: 4px;
  --unify-paybylink-button-hover-bg: #333;
  --unify-paybylink-button-hover-color: white;
  --unify-paybylink-button-hover-border-color: transparent;
  --unify-qrcode-size: 200px;
  --unify-qrcode-bg: white;
  --unify-qrcode-color: black;
}

To discover all available properties:

  1. Open browser DevTools
  2. Inspect the <unify-payment-widget> element
  3. Look at the Computed tab for all --unify-* entries
  4. Edit them live in the Styles panel to preview

CSS Parts

Structural elements can be targeted using ::part():

unify-payment-widget::part(payment-method-selector-option) {
  border-radius: 8px;
}

⚠️ Parts may change between versions. Use CSS custom properties where possible.

To find available parts, inspect the widget's shadow DOM in DevTools — every element with a part attribute is targetable from outside.

Events

payment-success

Fired when payment is confirmed by Unify. Only applies to 'cash-register' — the only method Unify actually processes itself.

widget.addEventListener('payment-success', (event) => {
  console.log('Method used:', event.detail.method);
});

Detail shape:

{
  method: string  // 'cash-register'
}

payment-link-ready

Fired for 'qrcode' / 'paybylink' once the QR code / link is generated and ready to show. This is not a payment confirmation — Unify doesn't process these two methods itself, the customer still has to open the link on their own device and complete payment there. Poll your own backend (or however you track completion of the payment behind link) to know when that actually happens.

widget.addEventListener('payment-link-ready', (event) => {
  console.log('Ready to show:', event.detail.method);
});

Detail shape:

{
  method: string  // 'qrcode' or 'paybylink'
}

payment-link-channel-selected

Fired when the customer picks the "Send by SMS" or "Send by Email" button for the "Pay by Link" method. The widget doesn't send anything itself — the integrator is expected to show its own form (phone number / email) and send the link.

widget.addEventListener('payment-link-channel-selected', (event) => {
  console.log('Send the link via', event.detail.channel, 'to order', event.detail.orderId);
});

Detail shape:

{
  channel: string,  // 'sms' or 'email'
  link: string,
  orderId: string
}

payment-error

Fired when payment processing encounters an error.

widget.addEventListener('payment-error', (event) => {
  console.error('Payment failed:', event.detail.error);
});

Detail shape:

{
  error: string,   // Error message
  method: string   // 'cash-register', 'qrcode' or 'paybylink'
}

Examples

const widget = document.querySelector('unify-payment-widget');

widget.config = {
  enabledPaymentMethods: ['cash-register', 'qrcode', 'paybylink'],
  cashRegisterPaymentMethodName: 'Pay at Register',
  qrcodePaymentMethodName: 'Scan to Pay',
  paybylinkPaymentMethodName: 'Pay by Link',
  qrCodeModuleShape: 'rounded',
};

// Required by the qrcode and paybylink methods — Unify does not generate or
// process the payment itself, the integrator provides this link.
widget.link = 'https://pay.example.com/checkout/BB4789507809478347';

widget.order = { /* order object from your Unify integration */ };

widget.addEventListener('payment-success', (event) => {
  console.log(`Payment completed via ${event.detail.method}`);
});

widget.addEventListener('payment-link-ready', (event) => {
  console.log(`${event.detail.method} link ready — waiting for the customer to pay`);
});

widget.addEventListener('payment-link-channel-selected', (event) => {
  console.log('Send the link via', event.detail.channel, 'to order', event.detail.orderId);
});

widget.addEventListener('payment-error', (event) => {
  console.error(`Payment failed: ${event.detail.error}`);
  widget.resetPayment();
});

Did this page help you?