PayPal

PayPal

PayPal is a platform that acts as an intermediary in online payment transactions, allowing users to make and receive payments securely and quickly.

In essence, PayPal simplifies the digital payment process by providing a secure, global, and convenient experience for buyers and sellers.


Supported operations

OperationDescription
Payment authorizationBlocks funds on the customer's card.
Payment captureCompletes the transaction and transfers the funds.
Direct paymentCombines authorization and capture in one step.
RefundReturns the full amount of a transaction.
Partial refundReturns part of the captured amount.
Authorization cancellationReverses an authorization that was not captured.

Integration

1. Configure PayPal as a payment method

To integrate PayPal, you must first perform a series of configurations from the OrkestaPay portal. Visit our Providers configuration guide and find the PayPal payment method.


2. Implement payment button

To tokenize the payment data, follow these steps:

  1. Include OrkestaPay scripts: Use the OrkestaPay scripts in your web application.
  2. Initialize parameters: Define the OrkestaPay credentials here, as well as data related to the payment to be processed.
  3. Render the payment button: Place the PayPal button in your frontend.

Required resources:

CSS

<link
  rel="stylesheet"
  href="https://checkout.orkestapay.com/web/components/payment-methods/styles.css"
  integrity="sha384-5/NLomvLQk75JVAmEdaNkdkgLavuAlRS256szA++bmuw6Zph/wFYlWFHz9Fss7JF"
  crossorigin="anonymous"
/>

JS

<script
  src="https://checkout.orkestapay.com/script/orkestapay.js"
  integrity="sha384-lQoLMYDY2Cz/Y+8BLiNbhfLVHWawqsA/gE/8WRTpF6ZS3EABNKXhrq/0bBu4M1aI"
  crossorigin="anonymous"
></script>

<script
  src="https://checkout.orkestapay.com/web/components/payment-methods/main.js"
  integrity="sha384-hvoIO7IyazX+Cc2LqBdHXx7Z3tq766248YzywLTN+D6f41Lub/VHUh2Pe5Q7WKfA"
  crossorigin="anonymous"
></script>

Code example

In the following code snippet there are certain parameters that need to be replaced with your merchant data:

  • public_key : Public key; these credentials can be obtained from the OrkestaPay portal.
  • merchant_id: Merchant ID; these credentials can be obtained from the OrkestaPay portal.
  • is_sandbox: Defines whether the credentials you are about to use are for testing or production.

In this example, sensitive credentials are captured in a form. These credentials must be handled from the backend.

  • client_id : This key, together with the secret key, will allow authentication to communicate with the OrkestaPay API. It is used on the server.
  • client_secret: This key, together with the access key, will allow authentication to communicate with the OrkestaPay API. It is used on the server.
📘

INFORMATION

To consult OrkestaPay credentials, you can visit our guide Get API keys.


<!DOCTYPE html>
<html lang="en">
  <head>
    <base href="/" />
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <link rel="apple-touch-icon" type="image/x-icon" href="favicon.ico" />
    <link rel="icon" type="image/x-icon" href="favicon.ico" />
    <title>PayPal web component</title>
    <link
      rel="stylesheet"
      href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
      integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
      crossorigin="anonymous"
    />
    <link rel="stylesheet" href="https://checkout.orkestapay.com/web/components/payment-methods/styles.css" />
    <style>
      .code {
        color: inherit;
        overflow-wrap: break-word;
        white-space: pre-wrap;
      }
    </style>
  </head>
  <body>
    <main class="container">
      <section class="row mt-5">
        <h1 id="card-title" class="col-12 text-center">OrkestaPay payment method PayPal web component</h1>
      </section>

      <section class="row">
        <article class="col-12 col-md-6 offset-md-3">
          <div class="row">
            <section class="pt-3 col-12 col-md-6">
              <label for="client-id" class="form-label"> OrkestaPay client ID&nbsp;<span class="text-danger">*</span> </label>
              <input type="text" id="client-id" class="form-control" />
              <small id="client-id-error" class="text-danger">&nbsp;</small>
            </section>

            <section class="pt-3 col-12 col-md-6">
              <label for="client-secret" class="form-label"> OrkestaPay client secret&nbsp;<span class="text-danger">*</span> </label>
              <input type="password" id="client-secret" class="form-control" />
              <small id="client-secret-error" class="text-danger">&nbsp;</small>
            </section>
          </div>
        </article>
        <article id="button-container" class="col-12 col-md-6 offset-md-3"></article>
        <article class="pt-3 col-12">
          <div id="payment-details" class="w-100 alert" role="alert"></div>
        </article>
      </section>
    </main>

    <noscript> Please enable JavaScript to continue using this application. </noscript>

    <script type="text/javascript" src="https://checkout.orkestapay.com/script/orkestapay.js"></script>
    <script type="text/javascript" src="https://checkout.orkestapay.com/web/components/payment-methods/main.js"></script>
    <script type="text/javascript">
      //#region FRONTEND

      let orkestaPay;
      let paymentId = null;

      const clientId = document.getElementById("client-id");
      const clientSecret = document.getElementById("client-secret");

      const { public_key, merchant_id, is_sandbox, country_code, currency, amount } = initValues();

      (async function main() {
        orkestaPay = initOrkestaPay({ is_sandbox, merchant_id, public_key });

        const payPalButton = document.createElement("orkestapay-paypal-button");
        await customElements.whenDefined("orkestapay-paypal-button");

        payPalButton.params = {
          payment_details: { currency, createPayment, confirmPayment },
          theme: {
            color: "gold",
            height: 48,
            shape: "rect",
          },
        };

        const container = document.getElementById("button-container");
        container.appendChild(payPalButton);
      })();

      function handlePaymentCreated(payment) {
        const code = document.createElement("code");
        code.innerHTML = JSON.stringify(payment, null, 2);
        code.classList.add("code");

        const paymentDetails = document.getElementById("payment-details");
        paymentDetails.classList.add("alert-success");
        paymentDetails.replaceChildren(code);

        paymentId = payment.payment_id;
        return paymentId ?? null;
      }

      function initValues() {
        const url = new URL(window.location.href);
        return {
          public_key: "<REPLACE_WITH_YOUR_PUBLIC_KEY>",
          merchant_id: "<REPLACE_WITH_YOUR_MERCHANT_ID>",
          is_sandbox: true,
          country_code: "MX",
          currency: "MXN",
          amount: "100.00",
        };
      }

      //#endregion FRONTEND

      //#region BACKEND

      async function createPayment(paymentMethod) {
        if (!paymentMethod) return null;
        const { payment_method_id } = paymentMethod;

        const order = await createOrder();
        if (!order) return null;
        const { order_id } = order;

        const deviceInfo = await orkestaPay.getDeviceInfo();
        if (!deviceInfo) return;
        const { device_session_id } = deviceInfo;

        const url = `${orkestaPay.getApiUrl()}/v1/payments`;
        const Authorization = await authenticate();
        const body = JSON.stringify({
          payment_source: { type: "PAYPAL", payment_method_id },
          device_session_id,
          order_id,
        });

        return fetch(url, {
          method: "POST",
          headers: {
            Authorization,
            "Content-Type": "application/json",
            "Idempotency-Key": crypto.randomUUID(),
          },
          body,
        })
          .then(handleFetchResponse)
          .then(handlePaymentCreated)
          .catch(handleFetchError);
      }

      async function confirmPayment() {
        if (!paymentId) return;

        const url = `${orkestaPay.getApiUrl()}/v1/payments/${paymentId}/confirm`;
        const Authorization = await authenticate();
        const body = JSON.stringify({});

        return fetch(url, {
          method: "POST",
          headers: {
            Authorization,
            "Content-Type": "application/json",
            "Idempotency-Key": crypto.randomUUID(),
          },
          body,
        })
          .then(handleFetchResponse)
          .then(handlePaymentCreated)
          .catch(handleFetchError);
      }

      async function createOrder() {
        const url = `${orkestaPay.getApiUrl()}/v1/orders`;
        const Authorization = await authenticate();
        const body = JSON.stringify({
          merchant_order_id: crypto.randomUUID(),
          subtotal_amount: amount,
          total_amount: amount,
          country_code,
          customer: {
            email: "[email protected]",
          },
          currency,
          products: [
            {
              product_id: crypto.randomUUID(),
              quantity: 1,
              unit_price: amount,
              name: "A random product",
            },
          ],
        });

        return fetch(url, {
          method: "POST",
          headers: { Authorization, "Content-Type": "application/json" },
          body,
        })
          .then(handleFetchResponse)
          .catch(handleFetchError);
      }

      async function authenticate() {
        const url = `${orkestaPay.getApiUrl()}/v1/oauth/tokens`;
        const body = JSON.stringify({
          client_id: clientId.value.trim(),
          client_secret: clientSecret.value.trim(),
          grant_type: "client_credentials",
        });

        const response = await fetch(url, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body,
        })
          .then(handleFetchResponse)
          .catch(handleFetchError);
        if (!response) return null;

        const { token_type, access_token } = response;
        return `${token_type} ${access_token}`;
      }

      function handleFetchResponse(response) {
        return response.ok ? response.json() : Promise.reject(body);
      }

      function handleFetchError(error) {
        console.error(error);
        return null;
      }

      //#endregion BACKEND
    </script>
  </body>
</html>
📘

NOTE

This code is for demonstration purposes only, integrating frontend code and code that should be executed from a backend. Therefore, it is your responsibility to implement with best practices.


Code explanation

Initial Variables and Functions

  • orkestaPay: Main object to interact with the OrkestaPay API.
  • paymentId: Stores the current payment ID.
  • initValues(): Initial configuration, such as keys and transaction details (amount, currency, etc.).

main function

  • Self-executing function that:
    1. Initializes OrkestaPay with initial values.
    2. Creates a PayPal button as a Web Component (<orkestapay-paypal-button>).
    3. Configures button parameters:
      • payment_details: Defines functions to create and confirm payments.
      • theme: Visual customization (color, shape, height).
    4. Adds the button to the container (button-container).

Backend operations

Authentication (authenticate)
  • Generates an access token:
    • Sends the client credentials (client_id and client_secret) to the API.
    • Returns a token used to authorize requests.

Order registration (createOrder)
  • Creates a new order:
    • Includes basic information such as total amount, currency, and products (fictional in this case).

Payment creation (createPayment)
  • Receives a payment method (paymentMethod).
  • Steps:
    1. Registers an order (createOrder).
    2. Obtains device information.
    3. Sends a POST request to the API to create a payment.
    4. Handles the response and updates the payment details (handlePaymentCreated).

Payment confirmation (confirmPayment)
  • Confirms the previously created payment via its paymentId.

Response and error handling

  • handleFetchResponse(response): Returns the response body if successful; otherwise, rejects the promise.
  • handleFetchError(error): Displays errors in the console.

Testing

To complete an integration test you must have a personal PayPal sandbox account.

📘

NOTE

For more information about testing with PayPal, refer to their official documentation: https://developer.paypal.com/tools/sandbox/