Docs · Website checkout integration

Use PayPortal as your checkout

This guide shows you how to add a “Pay with card” button to your own website and send customers through PayPortal for secure payment.

Overview

PayPortal lets you accept card payments and settle in crypto without changing your existing site. You keep your current product pages and cart. When a customer is ready to pay, your backend calls our API, gets back a checkout URL, and your front end redirects them to PayPortal.

Production base URL: https://api.payportal.uk

What you need

If you do not have your API key yet, reach out to PayPortal and we will send it to you.

How it works

  1. Your site totals the order (cart total in USD).
  2. Your front end calls your backend, sending amount + optional customer/cart info.
  3. Your backend calls /v1/checkout-session with your PayPortal API key.
  4. PayPortal returns a checkoutUrl and sessionId to your backend.
  5. Your backend returns checkoutUrl to the front end, which redirects the customer.
  6. Once paid, the order shows up in your PayPortal dashboard with status and order details.

Step 1 – Front-end button (no API key)

This runs in your front end and calls your backend. Your PayPortal API key never appears in browser-side JavaScript.

<button id="payportal-btn">
  Pay with card via PayPortal
</button>

<script>
  async function startPayPortalCheckout() {
    // Example: get cart total from your site
    const cartTotal = 49.99; // replace with your real cart total in USD

    // Optional: attach customer and cart details for your backend to forward
    const payload = {
      amount: cartTotal,
      note: "Order #1234",
      customer: {
        name: "Customer Name",
        email: "customer@example.com",
        phone: "+1-555-123-4567",
        address: {
          line1: "123 Main St",
          line2: "",
          city: "Richmond",
          state: "VA",
          postalCode: "23220",
          country: "US"
        }
      },
      cart: [
        {
          sku: "SKU123",
          name: "Example product",
          quantity: 1,
          unitPrice: 49.99
        }
      ]
    };

    try {
      // Call YOUR backend, not PayPortal directly
      const res = await fetch("/create-payportal-checkout", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(payload)
      });

      const data = await res.json();

      if (!res.ok || !data.checkoutUrl) {
        console.error("Checkout error:", data);
        alert("Could not create checkout. Please try again.");
        return;
      }

      // Optional: data.sessionId if your backend forwards it
      console.log("PayPortal sessionId:", data.sessionId);

      // Redirect customer to PayPortal checkout
      window.location.href = data.checkoutUrl;
    } catch (err) {
      console.error("Network error:", err);
      alert("Network error. Please try again.");
    }
  }

  document
    .getElementById("payportal-btn")
    .addEventListener("click", startPayPortalCheckout);
</script>

Request payload (from your backend to PayPortal)

Field Description
amount required Total charge to the customer in USD as a number (for example 49.99).
note optional Short description such as order number or customer name.
customer optional Object with customer info: name, email, phone, address (line1, line2, city, state, postalCode, country).
cart optional Array of cart items. Each item: { sku, name, quantity, unitPrice }. These show up in your PayPortal dashboard.

Response from PayPortal

Your backend will receive a JSON response similar to:

{
  "checkoutUrl": "https://moonpay.hel.io/charge/...",
  "sessionId": "69233...",
  "baseAmount": 49.99
}

checkoutUrl is where you send the customer to pay. sessionId is what you will see in the PayPortal dashboard. baseAmount is the amount that will settle to your wallet (before network fees).

Step 2 – Backend example (Node / Express)

This is an example of how your backend can call PayPortal using your API key. You can adapt this to any server framework or language.

// Node/Express example
import express from "express";
import fetch from "node-fetch";

const app = express();
app.use(express.json());

// Keep your PayPortal API key on the server only
const PAYPORTAL_API_KEY = "pk_YourPortalKeyHere";

app.post("/create-payportal-checkout", async (req, res) => {
  try {
    const payload = req.body; // { amount, note, customer, cart }

    const ppRes = await fetch("https://api.payportal.uk/v1/checkout-session", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "x-api-key": PAYPORTAL_API_KEY
      },
      body: JSON.stringify(payload)
    });

    const data = await ppRes.json();

    if (!ppRes.ok || !data.checkoutUrl) {
      console.error("PayPortal error:", data);
      return res.status(500).json({ error: "PayPortal checkout failed" });
    }

    // Forward only what the front end needs
    res.json({
      checkoutUrl: data.checkoutUrl,
      sessionId: data.sessionId,
      baseAmount: data.baseAmount
    });
  } catch (e) {
    console.error(e);
    res.status(500).json({ error: "Server error" });
  }
});

// Start your server
app.listen(3000, () => {
  console.log("Server listening on http://localhost:3000");
});

Step 3 – Match PayPortal sessions to your orders

If you run your own order system, you may want to link your internal order to the PayPortal payment. There are two easy ways to do this.

Option 1 – Use the note field

Set the note to your internal order number or identifier:

const payload = {
  amount: cartTotal,
  note: "Order #" + internalOrderId,
  ...
};

This note appears in the PayPortal dashboard when you view the transaction details, so you can quickly match them.

Option 2 – Store the sessionId

When you create a checkout session, PayPortal returns sessionId. You can store that on your side next to the order.

const data = await res.json();
saveOrder({
  orderId: internalOrderId,
  payportalSessionId: data.sessionId
});

Later, when you look at the PayPortal dashboard, you can search by sessionId to match an order.

Step 4 – View payments and mark orders fulfilled

If you later want a more advanced flow (for example your backend automatically marking orders fulfilled through the PayPortal API), reach out and we can provide an additional endpoint for that.

Security notes

Support

If you get stuck integrating PayPortal, send us:

We can usually tell what is wrong just from that.