Apple Pay with web components
Introducing Web Component Apple Pay
To simplify Apple Pay on the web, Jupico provides a reusable, framework-agnostic <apple-pay-jupico>
component. You embed one script and drop a single tag to render the native Apple Pay button, handle merchant validation, present the sheet, and return a short-lived token (or payment payload) on success.
Prerequisites (like Stripe):
- Serve over HTTPS.
- Register your domain(s) to use Apple Pay on the Web.
- Have an Apple Merchant ID and the required Apple Pay certificates.
- Apple Pay only appears on eligible devices/browsers (Safari/iOS/macOS with Wallet set up).
🛠️ Step-by-Step Guide
1️⃣ Add Jupico’s JavaScript Library
Include the hosted bundle that registers the Apple Pay component:
<head>
<meta charset="UTF-8" />
<!-- 👇🏻 Add Jupico hosted script (Apple Pay button is included here or in a sibling bundle) -->
<script src="https://sandbox-payments-hosted-pages.jupico.com/wc/tokenization-form.umd.js"></script>
<!-- If your environment separates Apple Pay, use:
<script src="https://sandbox-payments-hosted-pages.jupico.com/wc/apple-pay-jupico.umd.js"></script>
-->
</head>
2️⃣ Include the Web Component
Use the <apple-pay-jupico>
tag and pass the required properties.
<apple-pay-jupico
id="apple-pay-btn"
:sessions="{YOUR_SESSIONS_OBJECT}"
:transactionComplete="handleApplePayAuthorization"
/>
// Vanilla JavaScript
document.addEventListener("DOMContentLoaded", function () {
fetch("https://your-appserver.com/browser-session-authorize", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ publicKey: "YOUR_PUBLIC_KEY",
"applePay": {
"enabled": true,
"amount": 23,
"description": "test applePay"
}
})
.then(res => res.json())
.then(res => {
const el = document.createElement("apple-pay-jupico");
el.id = "apple-pay-btn";
el.sessions = res?.data?.sessions; // required
el.transactionComplete = handleApplePayAuthorization; // required
document.getElementById("apple-pay-container").appendChild(el);
})
.catch(err => console.error("Error:", err));
});
🔹 Required Properties
sessions
: opaque authorization sessions object from your backend (don’t modify it).transaction-complete
: callback invoked when the Apple Pay sheet finishes (success/cancel/error).
Like Stripe’s web flow, the component performs merchant validation and presents the Apple Pay sheet on user click. Apple requires a user gesture to open the sheet.
3️⃣ (Optional) Manually Trigger From a Button
The component renders a native Apple Pay button and handles the click itself. If you prefer an external trigger, expose a handler that calls the component’s internal action (if available in your build):
<button id="pay-with-apple">Pay with Apple Pay</button>
<script>
document.getElementById("pay-with-apple").addEventListener("click", () => {
const el = document.getElementById("apple-pay-btn");
// If your build exposes an imperative method (optional):
el?._instance?.exposed?.present?.();
// Otherwise, rely on the built-in Apple Pay button rendered by the component.
});
</script>
4️⃣ Handle Completion (Success / Error)
Your callback receives the result of the Apple Pay authorization. On success, you’ll typically get a short-lived token (or an Apple Pay payment payload) to send to your server.
function handleApplePayAuthorization(event) {
// Inspect to learn the exact payload shape for your environment
console.log("🍏 Apple Pay result:", event);
if (event?.status === "authorized" || event?.success === true) {
const oneTimeToken =
event.oneTimeToken || event.paymentToken || event.token;
// Send to your backend to create the charge/authorization
fetch("https://your-appserver.com/applepay/confirm", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ paymentToken: oneTimeToken }),
})
.then(r => r.json())
.then(r => console.log("✅ Server confirmation:", r))
.catch(err => console.error("❌ Server error:", err));
} else if (event?.status === "canceled") {
console.warn("⛔️ User canceled Apple Pay.");
} else {
console.error("❌ Apple Pay error:", event?.error || event);
}
}
Server-side (like Stripe’s “Submit the payment” step): Always decide the amount on the server and complete the transaction there using the token you received.
🔹 Full Integration Code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Apple Pay (Web) – Jupico</title>
<!-- Jupico hosted script (registers the web components) -->
<script src="https://sandbox-payments-hosted-pages.jupico.com/wc/tokenization-form.umd.js" charset="utf-8"></script>
<!-- Or, if separated in your env:
<script src="https://sandbox-payments-hosted-pages.jupico.com/wc/apple-pay-jupico.umd.js" charset="utf-8"></script>
-->
</head>
<body>
<div id="apple-pay-container"></div>
<script>
document.addEventListener("DOMContentLoaded", function () {
// 1) Get sessions from your backend (your server does the B2B authorize call)
fetch("https://your-appserver.com/browser-session-authorize", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ publicKey: "YOUR_PUBLIC_KEY" }),
})
.then(response => response.json())
.then(response => {
// 2) Create the Apple Pay component
const applePayEl = document.createElement("apple-pay-jupico");
applePayEl.id = "apple-pay-btn";
applePayEl.sessions = response?.data?.sessions;
applePayEl.transactionComplete = handleApplePayAuthorization;
document.getElementById("apple-pay-container").appendChild(applePayEl);
})
.catch(error => console.error("Init error:", error));
// 3) Completion handler (success/cancel/error)
function handleApplePayAuthorization(event) {
console.log("handleApplePayAuthorization", event);
if (event?.status === "authorized" || event?.success === true) {
const token = event.oneTimeToken || event.paymentToken || event.token;
// Complete payment on your server
fetch("https://your-appserver.com/applepay/confirm", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ paymentToken: token }),
})
.then(r => r.json())
.then(r => console.log("Server confirmation:", r))
.catch(err => console.error("Server error:", err));
} else if (event?.status === "canceled") {
console.warn("User canceled Apple Pay");
} else {
console.error("Apple Pay error:", event?.error || event);
}
}
});
</script>
</body>
</html>
Notes & Parallels with Stripe
- Availability checks: As with Stripe, Apple requires device support + a card in Wallet. Your component only renders/enables the button when Apple Pay is available (Safari/iOS/macOS).
- Merchant validation & domain registration: Similar to Stripe’s flow, the provider handles merchant validation, but you must ensure your domains are registered and your Apple Merchant ID/certificates are correctly set up.
- User gesture: Present the Apple Pay sheet from a direct user action (button click).
- Server-side confirmation: Just like Stripe’s PaymentIntent step, finalize the payment on your server with the token emitted by
transactionComplete
. - Testing: Use an Apple Pay-capable device/browser and a properly configured sandbox setup. If the button doesn’t appear, check domain registration, HTTPS, device support, and session validity.
Vue snippet (matches your request)
<apple-pay-jupico
:sessions="sessionsObject"
:transactionComplete="handleApplePayAuthorization"
/>
<script setup>
function handleApplePayAuthorization(event) {
console.log("🍏 Apple Pay:", event);
if (event?.status === "authorized" || event?.success === true) {
const token = event.oneTimeToken || event.paymentToken || event.token;
// Send to backend
// await fetch("/applepay/confirm", { method: "POST", body: JSON.stringify({ paymentToken: token }) })
}
}
</script>
If you want, I can also add a tiny backend stub (Node/Express or your stack) that receives paymentToken
and completes the Apple Pay charge/authorization.
Updated about 4 hours ago