Skip to content

Add the payment widget to your site

Load the Leapa widget, render a payment form, and read the result.

The Leapa widget is a custom HTML element that renders a payment form inside your own page. The payer’s browser sends card numbers straight to Leapa, so your site never stores or forwards them. This page takes you from an empty page to a working form.

This is what your payer sees. Ten lines of HTML put it on the page, and Leapa handles the card details, the bank’s identity check and the receipt:

The Leapa card form: name and email fields, a card number field, expiry and security code, a billing address, a terms checkbox and a Charge button, with a Secured by Leapa badge underneath
The card form in charge mode, at 400px wide. Every label follows the lang attribute, and every colour follows your own.

Before you start

You need three things:

  • A Leapa account with a currency account in the currency you want to charge
  • An API key issued for that currency account, from your account settings
  • A page whose HTML you can edit

Your API key is a JSON Web Token (JWT), a signed string that records a few facts about you. The widget reads two of them. Your merchant country decides which payment methods appear, and the key itself says whether it is live or test.

Build against a test key

On every render the widget prints its environment and version to the browser console, as [LEAPA:ENV]: Test - version: v3.2.0. Read that line to confirm which key loaded. Switch to your live key only after both onSuccess and onFailure do what you expect on your own page.

The widget serves two merchant countries:

With a key issued for any other country, the widget shows the payer a banner instead of a form, and names the country on your console.

Put the form on the page

Three steps: load the widget, place the element, listen for the result.

Load the widget

Add both tags to the <head> of your page:

<script type="module" src="https://widgets.leapa.co/v3.2.0/customer.js"></script>
<link rel="stylesheet" href="https://widgets.leapa.co/v3.2.0/customer.css" />

The script defines the element. The stylesheet is 48 bytes and holds one rule, which hides the element until the script claims it.

Ask for the version by name

Both URLs name v3.2.0, and yours should too. A URL with no version in it follows whatever Leapa published last, so a release you did not ask for can change your checkout on a Tuesday morning. Pinning means you decide when that happens.

Keep both tags

Drop the stylesheet and your page shows an empty inline box for a moment, laid out by your own CSS rather than by the widget.

Add the element

Put the element where you want the form to appear:

<leapa-customer
  id="leapa"
  api-key="your_api_key_here"
  mode="charge"
  currency="BIF"
  amount="5000"
  description="Order 1234567890123"
  tos="true"
  badge="light"
></leapa-customer>

Three attributes are required in every mode: api-key, mode and description. Each mode adds one of its own: amount for charge, invoice-id for invoice, currency for add. Set currency anyway in the other two, because it is sent with the payment and it decides whether BurundiPay can appear.

The widget checks all of that before it renders. A rule that fails replaces the whole form with this banner:

A red banner in place of the payment form, reading “We’re unable to display the payment form. Please contact the merchant for assistance.”
The banner tells the payer to contact you, and nothing else. The widget names the failing attribute on your browser console instead, prefixed [LEAPA WIDGET].

The banner is deliberately vague, because the payer cannot fix an attribute and should not read your configuration. Open the console to find out which rule failed. Only the first failing rule is reported, so fix them one at a time.

The id matters when you place more than one widget on the same page. Give each one a different id so your event listeners can tell them apart.

Read the result

The widget reports back through two events on the element: onSuccess when Leapa accepts the payment, and onFailure when it does not.

<script>
  const widget = document.getElementById("leapa");
 
  widget.addEventListener("onSuccess", (event) => {
    console.log(event.detail);
  });
 
  widget.addEventListener("onFailure", (event) => {
    console.error(event.detail);
  });
</script>

The widget already shows the payer a green or red banner, so you do not have to render the outcome yourself. Use these events for the work only your site can do: store the customer ID you got back, mark an order paid, or send the payer to a thank-you page. Events and responses documents what event.detail holds in each case.

What the card form asks for

The card form always collects the card number, expiry, security code and a billing address. On top of that it shows a first name, a last name and an email field.

Pass a real value for any of those three and the widget fills it in and hides the field:

<leapa-customer
  id="leapa"
  api-key="your_api_key_here"
  mode="charge"
  currency="BIF"
  amount="5000"
  description="Order 1234567890123"
></leapa-customer>

The second form asks only for the card and the address. The widget sends the name and email with the payment:

The same card form with the first name, last name and email fields gone, starting at Name on card
The same form with first-name, last-name and email supplied. Three fewer fields for the payer to fill.

Two more attributes change the form. dob="true" adds a date of birth field, which is otherwise absent. tos="true" adds a required checkbox linking to Leapa’s terms of service, above the button. Widget attributes covers every combination.

The three modes

The mode attribute decides what the form does when the payer submits it.

Save a payment method with add

Use add to store a customer and a card for later, without taking money now:

<leapa-customer
  id="leapa"
  api-key="your_api_key_here"
  mode="add"
  currency="BIF"
  description="Save card for future orders"
  tos="true"
></leapa-customer>

The widget creates the customer, saves the card, and returns both objects. When a customer with that email already exists, it adds the card to that customer instead of failing. To add a second card to a customer you already know, pass customer-id and leave email out.

Visa cards register through a zero-amount charge, which is why an add form still needs a currency.

Take a payment with charge

Use charge to take money now. Add amount to the required set:

<leapa-customer
  id="leapa"
  api-key="your_api_key_here"
  mode="charge"
  currency="USD"
  amount="25"
  description="Two nights, room 12"
  tos="true"
></leapa-customer>

Amounts are in the main unit, not in cents

The example above charges 25.00 USD. Each currency has a floor and a ceiling, listed in Amount limits. An amount outside them shows a banner instead of the form.

Pay an existing invoice with invoice

Use invoice when you have already created an invoice in Leapa and want the payer to settle it:

<leapa-customer
  id="leapa"
  api-key="your_api_key_here"
  mode="invoice"
  invoice-id="your_invoice_id_here"
  currency="BIF"
  amount="45000"
  description="Room 204, two nights"
></leapa-customer>

invoice-id is required here. amount is not, but pass it anyway: BurundiPay puts the figure on the Pay button, so a payer approving a request sees what they are approving.

Invoice mode is also the only mode that offers BurundiPay. Both of its rails settle against an invoice, so a Burundi merchant charging directly sees card alone.

Choose which payment methods appear

By default the widget offers every method the merchant’s country supports, and shows a chooser only when there is more than one:

Two tiles above the payment form, Card and BurundiPay, with Card selected
A Burundi merchant on a BIF invoice. The chosen tile swaps the form below it; the Secured by Leapa badge stays put.

Set source-type to pin one method and drop the chooser:

ValueWhat the payer gets
allEvery method the country supports. This is the default
cardThe card form only
burundipayBurundiPay, with both of its rails on one screen
burundipay-qrBurundiPay, pinned to the QR code
burundipay-phoneBurundiPay, pinned to the phone request

A Cameroon merchant on the default gets a card form and no chooser, because Cameroon supports card alone. A Burundi merchant on a BIF invoice gets both tiles, if their account is enabled for instant bank payments.

A pinned method never falls back

Pin a method the country does not support and the widget shows a banner rather than serving card in its place. That is deliberate: a page that quietly serves something else hides a broken integration.

Language and appearance

Set lang to translate every label, placeholder and error message. English and French are supported, and the widget follows the attribute when you change it after load:

<leapa-customer id="leapa" lang="fr" api-key="your_api_key_here"></leapa-customer>
The same card form with French labels: Nom sur la carte, Numéro de carte, Adresse ligne 1, Ville, Pays, and a Payer button
The same element with lang set to fr. Labels, placeholders, validation messages and the button all follow.

Set theme to light, dark, or auto to follow the payer’s device. Leaving it out gives you a transparent background that sits on whatever your page paints behind it. You can also recolour the form to match your brand with CSS custom properties. Theming covers both.

What 3D Secure means for your checkout

3D Secure (3DS) is an extra identity check that card networks run during a card payment. You know it by its brand names, Visa Secure and Mastercard Identity Check. The widget runs it for you on every card payment, and there is nothing to configure.

Card-not-present payments, meaning any payment where nobody swipes the physical card, are more open to fraud than in-person ones. 3DS shifts that risk by asking the bank to confirm the payer is the real cardholder before the payment goes through.

When the bank wants that confirmation, it takes over the screen and asks for a code it sent to the payer’s phone or email:

A Verified by Visa challenge from the payer’s bank, shown over the merchant’s page

Not every payment is challenged. The bank decides, and a payment can pass without the payer seeing anything. Either way the widget waits for the outcome and then fires onSuccess or onFailure, so your code handles both paths the same way.

BurundiPay does not use 3DS. The payer approves in their bank app instead.

Test before you go live

A test key runs against Leapa’s test environment and the card networks’ staging authentication service, so no real money moves. These are the gateway test card numbers:

Card numberPays as
4456530000001096Visa
5123450000000008Mastercard, in XAF

Any future expiry date and any three-digit security code work with them.

Localhost talks to a different API

On localhost the widget calls Leapa’s development API rather than the production one. Use a key issued for that environment while you build, and re-test on a deployed URL before you ship.

View as markdown
Last updated