# Implementation

Learn how to use the PayPal component in your project.

## Overview

Every component follows the same basic three-step lifecycle:

1. Create the component and optionally add your own configuration.
2. Mount the component. This is what makes the component visible and interactive.
3. Unmount the component. This is a clean-up step that clears up resources.


## Before you start

To use the PayPal component, you first need to:

* [Install Components for Web](/guides/components/web/install).
* Complete the [PayPal onboarding](/guides/components/web/paypal/onboarding) process in the Unity Portal.


## Step 1: Initialise the SDK

To get started, initialise the Checkout SDK.


```typescript
const pxpCheckoutSdk = PxpCheckout.initialize({
  environment: "test",
  session: sessionData,
  ownerId: "Unity",
  ownerType: "MerchantGroup",
  transactionData: {
    currency: "USD" as CurrencyType,
    amount: 25,
    entryType: "Ecom",
    intent: {
      paypal: "Purchase"
    },
    merchantTransactionId: crypto.randomUUID(),
    merchantTransactionDate: () => new Date().toISOString(),
  },
  onGetShopper: () => {
    return Promise.resolve({
      id: 'Shopper_01',
      email: 'customer@example.com',
      firstName: 'John',
      lastName: 'Doe'
    });
  },
  onGetShippingAddress: () => {
    return Promise.resolve({
      address: '123 Main Street',
      city: 'New York',
      state: 'NY',
      postalCode: '10001',
      countryCode: 'US'
    });
  }
})
```

| Property | Description |
|  --- | --- |
| `environment`string | The environment type.Possible values:`test`: For sandbox.`live`: For production. |
| `session`sessionData | Details about the checkout session. |
| `ownerId`string | The identifier of the owner related to the `ownerType`. |
| `ownerType`string | The type of owner.Possible values:`MerchantGroup``Merchant` `Site`  |
| `onGetShopper`function | Callback function to provide shopper data dynamically. Returns a Promise with shopper information. |
| `onGetShippingAddress`function | Callback function to provide shipping address data dynamically. Returns a Promise with shipping address information. |
| `transactionData`object | Details about the transaction. |
| `transactionData.currency`string (1-3 characters) | The currency code associated with the transaction, in ISO 4217 format. |
| `transactionData.amount`number | The transaction amount. |
| `transactionData.entryType`string | The entry type.Possible values:`Ecom``MOTO` |
| `transactionData.intent`object | The transaction intents for each payment method. |
| `transactionData.intent.paypal`string | The intent for PayPal transactions.Possible values:`Authorisation``Purchase` |
| `transactionData.merchantTransactionId`string | A unique identifier for this transaction. |
| `transactionData.merchantTransactionDate`string | The date and time of the transaction, in ISO 8601 format. |


## Step 2: Create the component configuration

Next, you're going to create the component configuration.


```typescript
const paypalConfig = {
  payeeEmailAddress: 'merchant@example.com',
  paymentDescription: 'Order #12345',
  shippingPreference: 'NO_SHIPPING',
  userAction: 'PAY_NOW',
  renderType: 'standalone',
  fundingSources: 'paypal'
  }
};
```

| Parameter | Description |
|  --- | --- |
| `payeeEmailAddress`string (≤ 254 characters) | Your email address. |
| `paymentDescription`string | A description of the payment. |
| `shippingPreference`string | The shipping details to use.Possible values:`NO_SHIPPING`: No shipping address required.`GET_FROM_FILE`: Get shipping address from PayPal account.`SET_PROVIDED_ADDRESS`: Use provided shipping address. |
| `userAction`string | The next step in the payment flow.Possible values:`PAY_NOW`: Immediate payment capture.`CONTINUE`: Continue to PayPal for payment. |
| `renderType`string | The type of button to render.Possible values:`standalone`: A single button. Choose this when there is only one payment method.`setOfButtons`: Multiple buttons. Choose this when there are multiple payment methods. |
| `fundingSources`string or array of string | The payment method(s) to support. If the `renderType` is `standalone`, it must be a string. If it's `setOfButtons`, then it must be an array of strings.Possible values:`paypal`: Standard PayPal payments.`venmo`: Venmo payments.`paylater`: PayPal Pay Later financing. |
| `shippingAddress`object | Details about the shipping address. You should provide this only when the `shippingPreference` is `SET_PROVIDED_ADDRESS`. |
| `shippingAddress.addressLine1`string (≤ 300 characters) | The first line of the shipping address. |
| `shippingAddress.addressLine2`string (≤ 300 characters) | The second line of the shipping address. |
| `shippingAddress.city`string | The city of the shipping address. |
| `shippingAddress.postalCode`string (≤ 60 characters) | The postal or ZIP code of the shipping address. |
| `shippingAddress.state`string | The state or province of the shipping address. |
| `shippingAddress.recipientName`string | The name of the recipient. |
| `shippingAddress.countryCode`string (2 characters) | The country code of the shipping address, in ISO-3166-1 alpha-2 format. |
| `shippingOptions`array of objects | Details about the shipping options. You should provide this only when the `shippingPreference` is `GET_FROM_FILE`. |
| `shippingOptions.id` string (≤ 127 characters) | The unique identifier for the shipping option. |
| `shippingOptions.label` string (≤ 127 characters) | The display name for the shipping option. |
| `shippingOptions.selected`boolean | Whether this shipping option is selected. |
| `shippingOptions.amounts`object | Details about the shipping option's pricing. |
| `shippingOptions.amounts.currencyCode`string | The currency code. |
| `shippingOptions.amounts.shipping`string | The shipping cost. |
| `shippingOptions.type`string (enum) | The shipping type.Possible values:`Shipping``Pickup``PickupInStore``PickupInPerson` |


## Step 3: Add the HTML container

To render the component, add the HTML container.


```html
<div id="paypal-button-container"></div>
```

## Step 4: Mount the component

For the component to be visible and functional, you need to mount it. Make sure to supply both the component name and the container name.


```typescript
const paypalButton = paymentSDK.create('paypal-button', paypalConfig);
paypalButton.mount('paypal-button-container');
```

At this point, your component is ready to use.

## Step 5: Handle the payment result

In order to complete the payment flow, you need to implement basic event handling.


```typescript
const paypalConfig = {
  // ... previous config
  onApprove: async (data, actions) => {
    try {
      // Process the approved payment
      const result = await processPayment(data.orderID);
      
      if (result.success) {
        // Redirect to success page or show confirmation
        window.location.href = '/payment-success';
      } else {
        // Handle processing failure
        showErrorMessage('Payment processing failed');
      }
    } catch (error) {
      console.error('Payment processing error:', error);
      showErrorMessage('Payment failed. Please try again.');
    }
  },
  
  onError: (error) => {
    // Handle payment errors
    console.error('Payment error:', error);
    showErrorMessage('Payment failed. Please try again.');
  },
  
  onCancel: (data) => {
    // Handle payment cancellation
    console.log('Payment cancelled by user');
    // Optionally redirect or display a message
  }
};
```

## Step 6: Unmount the component

Lastly, remember to unmount the component when it's no longer needed.


```typescript
paypalButton.unmount();
```

## What's next?

### Customise the look and feel

You can configure the appearance and behaviour of the PayPal component to fit your brand. We've documented all configurable parameters in the [Customisation](/guides/components/web/paypal/customisation) page.


```typescript
const paypalConfig = {
  renderType: 'standalone',
  payeeEmailAddress: 'merchant@example.com',
  paymentDescription: 'Premium Subscription',
  shippingPreference: 'NO_SHIPPING',
  userAction: 'PAY_NOW',
  fundingSources: 'paypal',
  locale: 'en-US',
  style: {
    layout: 'horizontal',
    color: 'blue',
    shape: 'pill',
    label: 'buynow',
    height: 45,
    borderRadius: 4
  },
  queryParams: {
    buyerCountry: 'US',
    debug: false
  }
};
```

### Add more event handling

The PayPal component emits events based on user interaction or validation. As seen in the steps above, you can implement callback functions to handle these events and perform actions, such as display success and error messages. For more information about all the available events, see the [Events](/guides/components/web/paypal/events) page.


```typescript
const paypalConfig = {
  onShippingAddressChange: (data, actions) => {
    console.log('Shipping address changed:', data);
    // Validate and potentially reject
    if (invalidAddress) {
      return actions.reject();
    }
  }
};
```

### Add error handling

Error handling is crucial for payment components because they deal with sensitive financial data and complex validation rules. They can happen due to issues with configuration, validation, authentication, or connectivity. For more details about error handling, see the [Errors](/guides/components/errors) page.


```typescript
try {
  const paypalConfig = {
    renderType: 'standalone',
    payeeEmailAddress: 'merchant@example.com',
    paymentDescription: 'Order #12345',
    shippingPreference: 'NO_SHIPPING',
    userAction: 'PAY_NOW',
    fundingSources: 'paypal'
  };

  const paypalComponent = sdk.create('paypal-button', paypalConfig);
  paypalComponent.mount('paypal-button-container');
  
} catch (error) {
  console.error('Failed to initialise PayPal payment component:', error);
  // Show fallback UI or error message to user
  document.getElementById('paypal-button-container').innerHTML = 
    '<p>Payment system temporarily unavailable. Please try again later.</p>';
}
```

### Subscribe to webhooks

To get real-time updates about PayPal transactions, you can [subscribe to the PayPal webhooks](/guides/get-started/about-webhooks).

## Complete example

Here's a complete example of the PayPal component being added to a website.


```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Simple PayPal Payment Example</title>
  <style>
    body {
      font-family: Arial, sans-serif;
      max-width: 600px;
      margin: 50px auto;
      padding: 20px;
      background-color: #f5f5f5;
    }

    .payment-container {
      background: white;
      padding: 30px;
      border-radius: 8px;
      box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
    }

    h1 {
      text-align: center;
      color: #333;
      margin-bottom: 30px;
    }

    #paypal-button-container {
      margin: 20px 0;
    }
  </style>
</head>
<body>
  <div class="payment-container">
    <h1>Complete your payment</h1>
    
    <!-- The PayPal button component will be mounted here -->
    <div id="paypal-button-container"></div>
  </div>

  <!-- Link to the SDK script -->
  <script src="https://your-domain.com/pxp-checkout-sdk.js"></script>
  
  <script>
    // Simple analytics function
    function trackEvent(eventName, data) {
      console.log('Analytics:', eventName, data);
    }

    // Initialise when page loads
    document.addEventListener('DOMContentLoaded', function() {
      // Initialise the SDK
      const pxpSdk = PxpCheckout.initialize({
        environment: 'sandbox',
        session: {
          sessionId: 'your-session-id-here',
          hmacKey: 'your-hmac-key-here',
          encryptionKey: 'your-encryption-key-here'
        },
        ownerType: 'MerchantGroup',
        ownerId: 'owner-123',
        transactionData: {
          amount: 1000,
          currency: 'USD',
          entryType: 'Ecom',
          intent: {
            paypal: 'Purchase'
          },
          merchantTransactionId: 'txn-' + Date.now(),
          merchantTransactionDate: () => new Date().toISOString()
        },
        onGetShopper: () => {
          // Return current shopper data - this could come from your app state, form, or API
          return Promise.resolve({
            id: 'shopper-123',
            email: 'customer@example.com',
            firstName: 'John',
            lastName: 'Doe',
            phoneNumber: '+1-555-0123'
          });
        },
        onGetShippingAddress: () => {
          // Return current shipping address - this could come from checkout form
          return Promise.resolve({
            address: '123 Main Street',
            city: 'New York',
            state: 'NY',
            postalCode: '10001',
            countryCode: 'US'
          });
        }
      });

      // Create the PayPal button component
      const paypalComponent = pxpSdk.create('paypal-button', {
        renderType: 'standalone',
        payeeEmailAddress: 'merchant@example.com',
        paymentDescription: 'Order #12345',
        shippingPreference: 'NO_SHIPPING',
        userAction: 'PAY_NOW',
        fundingSources: 'paypal',
        style: {
          layout: 'vertical',
          color: 'gold',
          shape: 'rect',
          label: 'paypal',
          height: 45
        },
        onApprove: function(data) {
          trackEvent('paypal_payment_approved', { orderId: data.orderID });
          alert('Payment successful!');
        },
        onCancel: function(data) {
          trackEvent('paypal_payment_cancelled', { orderId: data.orderID });
          console.log('Payment cancelled');
        },
        onError: function(error) {
          trackEvent('paypal_payment_error', { error: error.message });
          alert('Payment failed. Please try again.');
        }
      });

      // Mount the component
      paypalComponent.mount('paypal-button-container');

      // Unmount the component when the page is being unloaded
      window.addEventListener('beforeunload', function() {
        paypalComponent.unmount();
      });
    });
  </script>
</body>
</html>
```