Everything you need to integrate ePay - all in one place. Use our API, plugins, and guides to set up payments in your solution - no matter the platform.
Build a checkout for Android and iOS with Kotlin and Swift. Add card fields to your own layout and let ePay’s Native SDK handle card collection and the payment flow.
Explore Native SDKAt ePay, we build products we would love to integrate ourselves.
We're developers, and we know what it takes: Clear documentation, flexible tools, and a platform that fits your needs - whether you're working on a single webshop or managing multiple clients.
We’ve made it easy to integrate ePay - no matter which solution you choose. Our documentation guides you step-by-step:
1// -------------------------------
2// Hosted Fields Callback Functions
3// -------------------------------
4
5function clientReadyCallback(event) {
6 console.log("Hosted fields client is ready:", event);
7}
8
9function invalidSessionCallback(event) {
10 console.error("Invalid session detected:", event);
11 displayError("Invalid session detected", event);
12}
13
14function challengeIssuedCallback(event) {
15 console.log("A challenge has been issued:", event);
16}
17
18function transactionAcceptedCallback(event) {
19 onTransactionComplete(true);
20}
21
22function transactionDeclinedCallback(event) {
23 onTransactionComplete(false);
24}
25
26function clientRedirectCallback(event) {
27 return false; // Skipping redirects in the demo preview
28}
29
30function invalidInputCallback(event) {
31 console.error("Invalid input encountered:", event);
32 displayError("Invalid input encountered", event);
33}
34
35function inputValidityCallback(event) {
36 console.log("Input validity changed:", event);
37}
38
39function inputSubmitCallback(event) {
40 console.log("Input submitted:", event);
41}
42
43function sessionExpiredCallback(event) {
44 console.error("Session has expired:", event);
45 displayError("Session has expired", event);
46}
47
48function errorCallback(event) {
49 console.error("An error occurred in hosted fields:", event);
50 displayError("An error occurred in hosted fields", event);
51}
52
53// -------------------------------
54// Helper: Create UI Containers
55// -------------------------------
56
57function createUi() {
58 const fields = document.createElement("div");
59 fields.id = "fields";
60
61 const errorBlock = document.createElement("div");
62 errorBlock.id = "error-block";
63
64 document.body.appendChild(fields);
65 document.body.appendChild(errorBlock);
66
67 return { fields, errorBlock };
68}
69
70// -------------------------------
71// Helper: Display Errors
72// -------------------------------
73
74/**
75 * Appends a formatted error message to the error block.
76 *
77 * @param {string} description - A human-readable error description.
78 * @param {object} event - The event object containing error details.
79 */
80function displayError(description, event) {
81 const errorBlock = document.getElementById("error-block");
82 errorBlock.style.display = "block";
83
84 let title = "";
85 if (event && event.type) {
86 title += event.type;
87 }
88 if (event && event.errorCode) {
89 title += title ? " - " + event.errorCode : event.errorCode;
90 }
91 if (!title) {
92 title = "Error";
93 }
94
95 if (event && event.event) {
96 title += ` (Event: ${event.event})`;
97 } else {
98 title += " (Event: N/A)";
99 }
100
101 const errorItem = document.createElement("div");
102 errorItem.classList.add("error-item");
103
104 const titleEl = document.createElement("div");
105 titleEl.classList.add("error-title");
106 titleEl.textContent = title;
107
108 const descriptionEl = document.createElement("div");
109 descriptionEl.classList.add("error-description");
110 descriptionEl.textContent =
111 description ||
112 (event && event.message ? event.message : "No further details provided.");
113
114 errorItem.appendChild(titleEl);
115 errorItem.appendChild(descriptionEl);
116 errorBlock.appendChild(errorItem);
117}
118
119// -------------------------------
120// Payment Request Setup
121// -------------------------------
122
123const headers = new Headers();
124const demoApiKey = "test_93dc98ae-ff87-4671-a821-cda33fdfc26e"; // Demo API key: NEVER use this client-side in production
125
126headers.append("Content-Type", "application/json");
127headers.append("Accept", "application/json");
128headers.append("Authorization", `Bearer ${demoApiKey}`);
129
130const paymentData = {
131 pointOfSaleId: "0195a362-5bf4-7bb9-a419-2367fda11e6f",
132 amount: 100, // minor amount
133 currency: "DKK",
134 scaMode: "SKIP",
135};
136
137const requestOptions = {
138 method: "POST",
139 headers: headers,
140 body: JSON.stringify(paymentData),
141 redirect: "follow",
142};
143
144// -------------------------------
145// Helper: Dynamically Load External Module
146// -------------------------------
147
148/**
149 * Dynamically loads an external script module.
150 *
151 * @param {string} scriptUrl - The URL of the external module.
152 * @param {Function} onLoadCallback - A callback function to run once the module loads.
153 */
154function loadExternalModule(scriptUrl, onLoadCallback) {
155 const scriptEl = document.createElement("script");
156 scriptEl.type = "module";
157 scriptEl.src = scriptUrl;
158 scriptEl.onload = onLoadCallback;
159 document.body.appendChild(scriptEl);
160}
161
162// -------------------------------
163// Helper: Create Payment Button
164// -------------------------------
165
166/**
167 * Creates and appends a payment button to the DOM.
168 * The button text is set dynamically using the converted amount (major) and currency.
169 *
170 * @param {number} amount - The payment amount (in minor units).
171 * @param {string} currency - The currency code.
172 */
173function createPaymentButton(amount, currency) {
174 const majorAmount = (amount / 100).toFixed(2);
175
176 const button = document.createElement("button");
177 button.type = "button";
178 button.id = "payment-button";
179 button.textContent = `Pay ${majorAmount} ${currency}`;
180
181 button.addEventListener("click", () => {
182 epay.createCardTransaction();
183 });
184
185 const fieldsContainer = document.getElementById("fields");
186 fieldsContainer.insertAdjacentElement("afterend", button);
187}
188
189// -------------------------------
190// Helper: Handle Transaction Completed
191// -------------------------------
192
193/**
194 * Function to handle the display after a transaction is completed.
195 *
196 * @param {boolean} success - Indicates whether the transaction was successful.
197 */
198function onTransactionComplete(success) {
199 const fieldsContainer = document.getElementById("fields");
200 const paymentButton = document.getElementById("payment-button");
201
202 fieldsContainer.style.display = "none";
203 paymentButton.style.display = "none";
204
205 const messageContainer = document.createElement("div");
206 messageContainer.id = "transaction-message";
207 messageContainer.style.marginTop = "20px";
208
209 if (success) {
210 messageContainer.innerHTML = `
211 <h2>Payment Success</h2>
212 <p>Your transaction has been completed successfully.</p>
213 `;
214 } else {
215 messageContainer.innerHTML = `
216 <h2>Payment Failed</h2>
217 <p>We're sorry, but your transaction could not be completed.</p>
218 `;
219 }
220
221 if (fieldsContainer && fieldsContainer.parentNode) {
222 fieldsContainer.parentNode.appendChild(messageContainer);
223 } else {
224 document.body.appendChild(messageContainer);
225 }
226}
227
228// -------------------------------
229// Payment Request & Hosted Fields Initialization
230// -------------------------------
231
232createUi();
233
234fetch("https://payments.epay.eu/public/api/v1/cit", requestOptions)
235 .then((response) => response.json())
236 .then((result) => {
237 const sessionId = result.session.id;
238 const sessionKey = result.key;
239 const amount = result.session.amount;
240 const currency = result.session.currency;
241
242 loadExternalModule(result.javascript, () => {
243 epay
244 .setSessionId(sessionId)
245 .setSessionKey(sessionKey)
246 .setCallbacks({
247 clientReady: clientReadyCallback,
248 invalidSession: invalidSessionCallback,
249 challengeIssued: challengeIssuedCallback,
250 transactionAccepted: transactionAcceptedCallback,
251 transactionDeclined: transactionDeclinedCallback,
252 clientRedirect: clientRedirectCallback,
253 invalidInput: invalidInputCallback,
254 inputValidity: inputValidityCallback,
255 inputSubmit: inputSubmitCallback,
256 sessionExpired: sessionExpiredCallback,
257 error: errorCallback,
258 })
259 .init();
260
261 epay.mountFields("fields", {
262 // The configuration object can be added here when needed.
263 });
264
265 createPaymentButton(amount, currency);
266 });
267 })
268 .catch((error) => {
269 console.error("Error during payment request:", error);
270 displayError("Error during payment request", error);
271 });