Web Native Payment API with SvelteKit
Tags: javascript, webdev, svelte, sveltekit
Published: 2022-08-02 07:17:00

Read If:
- You are interested in payment integration in SvelteKit

**Resources**
- [Google Pay Button Example Source Code](https://github.com/google-pay/google-pay-button/tree/main/examples/svelte)
- [Web Payment Request Examples by Google](https://github.com/GoogleChrome/samples/tree/gh-pages/paymentrequest)
- [MDN Docs for Web Payment](https://developer.mozilla.org/en-US/docs/Web/API/Payment_Request_API)
- [Google Web Devs Docs](https://web.dev/payments/)

**Introduction**
This article is going to about how to do an hassle free payment integration to our project because we all know when we use all those 3rd party payment integration how much pain they are to handle and we might sometime don't like it to add it but don't have any options. That's where web native payment api comes in you just have to least things to handle that payment and here I'm gonna show you an example of doing that in SvelteKit and it's example from google payment sample. 

Here, we simply gonna use our `use` action of svelte to make it more easy for us.
As always first we gonna setup our SvelteKit Project. If you wanna learn how to then just [click here](https://dev.to/theether0/using-tailwindcss-in-sveltekit-to-make-a-design-system-part-one-4k3p).

After project setup please follow these setup.

**Setting initiate of the payment**

So here we just need to add a button which gonna use our `use` action and going to call the Javascript code that we going to add in our `lib/pay.js` file.

```html
// index.svelte
<script>
	import { payTest } from '../lib/pay.js';
</script>

<div><button id="buyButton" use:payTest>Buy</button></div>
<div><pre id="result" /></div>
```

As you can se I'm using `use` action to do my things here.

Now we will create a file in `lib` folder by the name `pay.js`. Now we gonna add few lines of code will do our hassling work.

```Javascript
/**
 * Builds PaymentRequest that also gathers user's shipping address, but does not
 * show any UI yet.
 *
 * @return {PaymentRequest} The PaymentRequest object.
 */
function initPaymentRequest() {
  let supportedInstruments = [{
    supportedMethods: 'https://bobbucks.dev/pay',
  }];

  let details = {
    total: {label: 'Donation', amount: {currency: 'USD', value: '55.00'}},
    displayItems: [
      {
        label: 'Original donation amount',
        amount: {currency: 'USD', value: '65.00'},
      },
      {
        label: 'Friends and family discount',
        amount: {currency: 'USD', value: '-10.00'},
      },
      {
        label: 'Free shipping worldwide',
        amount: {currency: 'USD', value: '0.00'},
      },
    ],
    shippingOptions: [{
      id: 'freeWorldwideShipping',
      label: 'Free shipping worldwide',
      amount: {currency: 'USD', value: '0.00'},
      selected: true,
    }],
  };

  let options = {requestShipping: true};

  let request = new PaymentRequest(supportedInstruments, details, options);

  request.addEventListener('shippingaddresschange', function(evt) {
    evt.updateWith(Promise.resolve(details));
  });

  return request;
}

/**
 * Invokes PaymentRequest that also gathers user's shipping address.
 *
 * @param {PaymentRequest} request The PaymentRequest object.
 */
function onBuyClicked(request) {
  request.show().then(function(instrumentResponse) {
    sendPaymentToServer(instrumentResponse);
  })
  .catch(function(err) {
    ChromeSamples.setStatus(err);
  });
}

/**
 * Simulates processing the payment data on the server.
 *
 * @private
 * @param {PaymentResponse} instrumentResponse The payment information to
 * process.
 */
function sendPaymentToServer(instrumentResponse) {
  // There's no server-side component of these samples. No transactions are
  // processed and no money exchanged hands. Instantaneous transactions are not
  // realistic. Add a 2 second delay to make it seem more real.
  window.setTimeout(function() {
    instrumentResponse.complete('success')
        .then(function() {
          document.getElementById('result').innerHTML =
              instrumentToJsonString(instrumentResponse);
        })
        .catch(function(err) {
          ChromeSamples.setStatus(err);
        });
  }, 2000);
}

/**
 * Converts the payment instrument into a JSON string.
 *
 * @private
 * @param {PaymentResponse} instrument The instrument to convert.
 * @return {string} The JSON string representation of the instrument.
 */
function instrumentToJsonString(instrument) {
  let details = instrument.details;

  return JSON.stringify({
    methodName: instrument.methodName,
    details: details,
    shippingAddress: addressToDictionary(instrument.shippingAddress),
    shippingOption: instrument.shippingOption,
  }, undefined, 2);
}

/**
 * Converts the shipping address into a dictionary.
 *
 * @private
 * @param {PaymentAddress} address The address to convert.
 * @return {object} The dictionary representation of the shipping address.
 */
function addressToDictionary(address) {
  if (address.toJSON) {
    return address.toJSON();
  }

  return {
    recipient: address.recipient,
    organization: address.organization,
    addressLine: address.addressLine,
    dependentLocality: address.dependentLocality,
    city: address.city,
    region: address.region,
    postalCode: address.postalCode,
    sortingCode: address.sortingCode,
    country: address.country,
    languageCode: address.languageCode,
    phone: address.phone,
  };
}

const payButton = document.getElementById('buyButton');
payButton.setAttribute('style', 'display: none;');
if (window.PaymentRequest) {
  let request = initPaymentRequest();
  payButton.setAttribute('style', 'display: inline;');
  payButton.addEventListener('click', function() {
    onBuyClicked(request);
    request = initPaymentRequest();
  });
} else {
  ChromeSamples.setStatus('This browser does not support web payments');
}
```
- Here first we are assign getting and assigning the button that will be clicked and our payment flow will init.

- initPaymentRequest function returns some values which will of Payment request type.
```javascript
new PaymentRequest(supportedInstruments, details, options);
```
1. supportedInstruments are the payment methods that you support and details are the data about your payment and options are optional where you can describe your requirements to payment api to show shipping field or not.

2. After that Web Native Payment will handle the all for you on the basis of provided data and options and will return all the response in the end.

That's all we have to do. This was the example from google payments example and there is something that will make your life more easy which is using `google-pay-button`. You can check it out in provided resources.

This is me writing for you. If you wanna ask or suggest anything please put it in comment.