diff --git a/config/application.properties b/config/application.properties
index 728551d..2316732 100644
--- a/config/application.properties
+++ b/config/application.properties
@@ -18,7 +18,18 @@ ADYEN_LEM_API_KEY=
## HMAC key to validate incoming webhook requests
ADYEN_HMAC_KEY=
+## URL of the Session Authentication API to create the session token required by Adyen AfP web components
+## https://docs.adyen.com/platforms/build-user-dashboards/
+##
+## Default: https://test.adyen.com/authe/api/v1/sessions
+ADYEN_SESSION_AUTHENTICATION_API_URL=https://test.adyen.com/authe/api/v1/sessions
+
## (Optional) Id of the Hosted Onboarding Theme created in the Customer Area
-# When undefined the default theme will be used
+## When undefined the default theme will be used
ADYEN_HOSTED_ONBOARDING_THEME_ID=
+## URL where the AfP components will appear
+## Examples: https://www.example.com | https://*.example.com | http://localhost
+##
+ADYEN_COMPONENTS_ALLOW_ORIGIN=
+
diff --git a/react-app/package-lock.json b/react-app/package-lock.json
index 230831e..aaec604 100644
--- a/react-app/package-lock.json
+++ b/react-app/package-lock.json
@@ -8,6 +8,7 @@
"name": "react-app",
"version": "0.1.0",
"dependencies": {
+ "@adyen/adyen-platform-experience-web": "^1.1.1",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0",
"@fontsource/roboto": "^5.1.0",
@@ -37,6 +38,18 @@
"resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.0.tgz",
"integrity": "sha512-Ff9+ksdQQB3rMncgqDK78uLznstjyfIf2Arnh22pW8kBpLs6rpKDwgnZT46hin5Hl1WzazzK64DOrhSwYpS7bQ=="
},
+ "node_modules/@adyen/adyen-platform-experience-web": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@adyen/adyen-platform-experience-web/-/adyen-platform-experience-web-1.1.1.tgz",
+ "integrity": "sha512-CV3HKyoq/vxsmcJZ75EV7EY+Vioocpq/1qP9ygelTzmUH4x7VaYQSXjZd8SV87WcA4AMAVN0krz5jUhNEvym3A==",
+ "dependencies": {
+ "classnames": "^2.5.1",
+ "core-js": "^3.36.0"
+ },
+ "peerDependencies": {
+ "preact": "^10.13.2"
+ }
+ },
"node_modules/@alloc/quick-lru": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
@@ -5676,6 +5689,11 @@
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz",
"integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ=="
},
+ "node_modules/classnames": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
+ "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
+ },
"node_modules/clean-css": {
"version": "5.3.2",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.3.2.tgz",
@@ -5892,9 +5910,9 @@
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
},
"node_modules/core-js": {
- "version": "3.33.0",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.33.0.tgz",
- "integrity": "sha512-HoZr92+ZjFEKar5HS6MC776gYslNOKHt75mEBKWKnPeFDpZ6nH5OeF3S6HFT1mUAUZKrzkez05VboaX8myjSuw==",
+ "version": "3.38.1",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.38.1.tgz",
+ "integrity": "sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==",
"hasInstallScript": true,
"funding": {
"type": "opencollective",
@@ -13021,6 +13039,16 @@
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
},
+ "node_modules/preact": {
+ "version": "10.24.2",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.2.tgz",
+ "integrity": "sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==",
+ "peer": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
diff --git a/react-app/package.json b/react-app/package.json
index 3635a4f..9453af7 100644
--- a/react-app/package.json
+++ b/react-app/package.json
@@ -3,6 +3,7 @@
"version": "0.1.0",
"private": true,
"dependencies": {
+ "@adyen/adyen-platform-experience-web": "^1.1.1",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0",
"@fontsource/roboto": "^5.1.0",
diff --git a/react-app/src/dashboard/Dashboard.js b/react-app/src/dashboard/Dashboard.js
index 82d6aa2..8a4d8dd 100644
--- a/react-app/src/dashboard/Dashboard.js
+++ b/react-app/src/dashboard/Dashboard.js
@@ -8,7 +8,6 @@ import Grid from "@mui/material/Grid";
import Toolbar from '@mui/material/Toolbar';
import Typography from '@mui/material/Typography';
import Divider from '@mui/material/Divider';
-import BarChartIcon from '@mui/icons-material/BarChart';
import { useNavigate } from 'react-router-dom';
diff --git a/react-app/src/dashboard/Transactions.js b/react-app/src/dashboard/Transactions.js
index 2795016..7008d06 100644
--- a/react-app/src/dashboard/Transactions.js
+++ b/react-app/src/dashboard/Transactions.js
@@ -8,131 +8,77 @@ import Divider from '@mui/material/Divider';
import { useNavigate } from 'react-router-dom';
import Paper from '@mui/material/Paper';
-import Table from '@mui/material/Table';
-import TableBody from '@mui/material/TableBody';
-import TableCell from '@mui/material/TableCell';
-import TableContainer from '@mui/material/TableContainer';
-import TableHead from '@mui/material/TableHead';
-import TablePagination from '@mui/material/TablePagination';
-import TableRow from '@mui/material/TableRow';
import DashboardHeader from "./DashboardHeader.js";
import DashboardDrawer from "./DashboardDrawer.js";
+import { AdyenPlatformExperience, TransactionsOverview } from '@adyen/adyen-platform-experience-web';
+import "@adyen/adyen-platform-experience-web/adyen-platform-experience-web.css";
+
export default function Products() {
const navigate = useNavigate()
- const [page, setPage] = useState(0);
- const [rowsPerPage, setRowsPerPage] = useState(10);
- const [rows, setRows] = useState([]);
-
- const handleChangePage = (event, newPage) => {
- setPage(newPage);
- };
-
- const handleChangeRowsPerPage = (event) => {
- setRowsPerPage(+event.target.value);
- setPage(0);
- };
-
- useEffect(() => {
- const fetchData = async () => {
- try {
- const response = await axios.post('/api/dashboard/getTransactions');
- setRows(response.data);
- } catch (error) {
- console.error('API request error:', error);
- navigate('/');
- }
- };
-
- fetchData();
- }, []);
-
- return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- {columns.map((column) => (
-
- {column.label}
-
- ))}
-
-
-
- {rows
- .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
- .map((row) => {
- return (
-
- {columns.map((column) => {
- const value = row[column.id];
- return (
-
- {column.format && typeof value === 'number'? column.format(value) : value}
-
- );
- })}
-
- );
- })}
-
-
-
-
-
-
-
-
-
+ async function sessionRequest() {
+ try {
+ const response = await fetch('/api/dashboard/getTransactions', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ });
+
+ if (!response.ok) {
+ throw new Error(`Error: ${response.status} ${response.statusText}`);
+ }
+
+ return await response.json();
+ } catch (error) {
+ console.error("sessionRequest error: ", error);
+ throw error;
+ }
+ }
+
+ async function initializeCore() {
+ const core = await AdyenPlatformExperience({
+ environment: 'test', // test or live
+ locale: 'en-US',
+ async onSessionCreate() {
+ const session = await sessionRequest();
+ return session;
+ }
+ });
+ const transactionsOverview = new TransactionsOverview({ core: core, preferredLimit: 10, allowLimitSelection: true });
+
+ transactionsOverview.mount('#transactions-overview-container');
+ }
+
+ initializeCore();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
}
-
-const columns = [
- { id: 'id', label: 'ID', minWidth: 100 },
- { id: 'status', label: 'Status', minWidth: 120 },
- { id: 'type', label: 'Type', minWidth: 120 },
- { id: 'created', label: 'Created', minWidth: 220 },
- { id: 'amount', label: 'Amount', minWidth: 150 },
-];
\ No newline at end of file
diff --git a/react-app/src/dashboard/TransactionsCustomView.js b/react-app/src/dashboard/TransactionsCustomView.js
new file mode 100644
index 0000000..2795016
--- /dev/null
+++ b/react-app/src/dashboard/TransactionsCustomView.js
@@ -0,0 +1,138 @@
+import React, { useState, useEffect } from 'react';
+import axios from "axios";
+
+import Box from '@mui/material/Box';
+import Chip from '@mui/material/Chip';
+import Toolbar from '@mui/material/Toolbar';
+import Divider from '@mui/material/Divider';
+import { useNavigate } from 'react-router-dom';
+
+import Paper from '@mui/material/Paper';
+import Table from '@mui/material/Table';
+import TableBody from '@mui/material/TableBody';
+import TableCell from '@mui/material/TableCell';
+import TableContainer from '@mui/material/TableContainer';
+import TableHead from '@mui/material/TableHead';
+import TablePagination from '@mui/material/TablePagination';
+import TableRow from '@mui/material/TableRow';
+
+import DashboardHeader from "./DashboardHeader.js";
+import DashboardDrawer from "./DashboardDrawer.js";
+
+export default function Products() {
+
+ const navigate = useNavigate()
+
+ const [page, setPage] = useState(0);
+ const [rowsPerPage, setRowsPerPage] = useState(10);
+ const [rows, setRows] = useState([]);
+
+ const handleChangePage = (event, newPage) => {
+ setPage(newPage);
+ };
+
+ const handleChangeRowsPerPage = (event) => {
+ setRowsPerPage(+event.target.value);
+ setPage(0);
+ };
+
+ useEffect(() => {
+ const fetchData = async () => {
+ try {
+ const response = await axios.post('/api/dashboard/getTransactions');
+ setRows(response.data);
+ } catch (error) {
+ console.error('API request error:', error);
+ navigate('/');
+ }
+ };
+
+ fetchData();
+ }, []);
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {columns.map((column) => (
+
+ {column.label}
+
+ ))}
+
+
+
+ {rows
+ .slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage)
+ .map((row) => {
+ return (
+
+ {columns.map((column) => {
+ const value = row[column.id];
+ return (
+
+ {column.format && typeof value === 'number'? column.format(value) : value}
+
+ );
+ })}
+
+ );
+ })}
+
+
+
+
+
+
+
+
+
+ );
+}
+
+const columns = [
+ { id: 'id', label: 'ID', minWidth: 100 },
+ { id: 'status', label: 'Status', minWidth: 120 },
+ { id: 'type', label: 'Type', minWidth: 120 },
+ { id: 'created', label: 'Created', minWidth: 220 },
+ { id: 'amount', label: 'Amount', minWidth: 150 },
+];
\ No newline at end of file
diff --git a/react-app/src/home/Home.js b/react-app/src/home/Home.js
index 97b85de..af12f8b 100644
--- a/react-app/src/home/Home.js
+++ b/react-app/src/home/Home.js
@@ -18,7 +18,7 @@ const card1 = (
-

+
@@ -35,7 +35,7 @@ const card2 = (
-

+
@@ -52,7 +52,7 @@ const card3 = (
-

+
diff --git a/react-app/src/index.css b/react-app/src/index.css
index ec2585e..e47ff11 100644
--- a/react-app/src/index.css
+++ b/react-app/src/index.css
@@ -1,13 +1,27 @@
body {
- margin: 0;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
- 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
- sans-serif;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
+ margin: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
}
code {
- font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}
+
+:root {
+ --adyen-sdk-color-outline-primary-active: lightgreen;
+ --adyen-sdk-color-background-inverse-primary: #0abf53;
+ --adyen-sdk-color-background-inverse-primary-hover: #57d389;
+ --adyen-sdk-color-background-disabled: #9ecdb1;
+ --adyen-sdk-border-radius-m: 20px;
+}
+
+.adyen-pe-modal {
+ border-radius: 0;
+ border-left: 3px solid lightgreen;
+ height: 100%;
+ right: 0;
+}
\ No newline at end of file
diff --git a/react-app/src/index.js b/react-app/src/index.js
index 94d8ae4..9513af1 100644
--- a/react-app/src/index.js
+++ b/react-app/src/index.js
@@ -5,6 +5,8 @@ import { ThemeProvider } from '@mui/material/styles';
import App from './App';
import theme from './theme';
+import "./index.css";
+
const rootElement = document.getElementById('root');
const root = ReactDOM.createRoot(rootElement);
diff --git a/src/main/java/com/adyen/config/ApplicationProperty.java b/src/main/java/com/adyen/config/ApplicationProperty.java
index 0030c0d..347c740 100644
--- a/src/main/java/com/adyen/config/ApplicationProperty.java
+++ b/src/main/java/com/adyen/config/ApplicationProperty.java
@@ -24,6 +24,12 @@ public class ApplicationProperty {
@Value("${ADYEN_HOSTED_ONBOARDING_THEME_ID}")
private String hostedOnboardingThemeId;
+ @Value("${ADYEN_SESSION_AUTHENTICATION_API_URL:https://test.adyen.com/authe/api/v1/sessions}")
+ private String sessionAuthenticationApiUrl;
+
+ @Value("${ADYEN_COMPONENTS_ALLOW_ORIGIN}")
+ private String componentsAllowOrigin;
+
public String getApiKey() {
return apiKey;
}
@@ -71,4 +77,20 @@ public String getHmacKey() {
public void setHmacKey(String hmacKey) {
this.hmacKey = hmacKey;
}
+
+ public String getSessionAuthenticationApiUrl() {
+ return sessionAuthenticationApiUrl;
+ }
+
+ public void setSessionAuthenticationApiUrl(String sessionAuthenticationApiUrl) {
+ this.sessionAuthenticationApiUrl = sessionAuthenticationApiUrl;
+ }
+
+ public String getComponentsAllowOrigin() {
+ return componentsAllowOrigin;
+ }
+
+ public void setComponentsAllowOrigin(String componentsAllowOrigin) {
+ this.componentsAllowOrigin = componentsAllowOrigin;
+ }
}
diff --git a/src/main/java/com/adyen/controller/DashboardController.java b/src/main/java/com/adyen/controller/DashboardController.java
index 0d99ec1..98fc43a 100644
--- a/src/main/java/com/adyen/controller/DashboardController.java
+++ b/src/main/java/com/adyen/controller/DashboardController.java
@@ -1,14 +1,14 @@
package com.adyen.controller;
-import com.adyen.model.OnboardingLinkProperties;
-import com.adyen.model.TransactionItem;
-import com.adyen.model.User;
+import com.adyen.config.ApplicationProperty;
+import com.adyen.model.*;
import com.adyen.model.balanceplatform.AccountHolder;
import com.adyen.model.legalentitymanagement.LegalEntity;
import com.adyen.model.legalentitymanagement.OnboardingLink;
import com.adyen.service.ConfigurationAPIService;
import com.adyen.service.LegalEntityManagementAPIService;
import com.adyen.util.LegalEntityHandler;
+import com.adyen.util.RestClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -32,6 +32,11 @@ public class DashboardController extends BaseController {
private LegalEntityManagementAPIService legalEntityManagementAPIService;
@Autowired
private LegalEntityHandler legalEntityHandler;
+ @Autowired
+ private RestClient restClient;
+ @Autowired
+ private ApplicationProperty applicationProperty;
+
/**
* Get User who has logged in (user id found in Session)
@@ -95,14 +100,55 @@ ResponseEntity getOnboardingLink(@RequestBody OnboardingLinkProperties o
);
}
+ /**
+ * Displays the AccountHolder transactions using the Adyen Transactions component
+ *
+ * This demonstrates how to integrate the Adyen web component that fetches and
+ * displays the transactions
+ *
+ * @return
+ */
@PostMapping("/getTransactions")
- ResponseEntity> getTransactions() {
+ ResponseEntity getTransactions() {
if (getUserIdOnSession() == null) {
log.warn("User is not logged in");
return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
}
+ // Perform session call to obtain a valid Session token
+ SessionRequest sessionRequest = new SessionRequest()
+ .allowOrigin(getApplicationProperty().getComponentsAllowOrigin())
+ .product("platform")
+ .policy(new SessionRequestPolicy()
+ .resources(List.of(new PolicyResource()
+ .accountHolderId(getUserIdOnSession())
+ .type("accountHolder")))
+ .roles(List.of("Transactions Overview Component: View")));
+
+ SessionResponse response = restClient.call(getApplicationProperty().getSessionAuthenticationApiUrl(), sessionRequest);
+
+ return new ResponseEntity<>(response, HttpStatus.ACCEPTED);
+ }
+
+ /**
+ * Displays the AccountHolder transactions in a custom view
+ *
+ * This demonstrates how to fetch the AccountHolder transactions via API and
+ * display them in a custom-built view
+ *
+ * @return
+ */
+ @PostMapping("/getTransactionsCustomView")
+ ResponseEntity> getTransactionsCustomView() {
+
+ if (getUserIdOnSession() == null) {
+ log.warn("User is not logged in");
+ return new ResponseEntity<>(HttpStatus.UNAUTHORIZED);
+ }
+
+
+
return new ResponseEntity<>(
getConfigurationAPIService().getTransactions(getUserIdOnSession()), HttpStatus.ACCEPTED);
}
@@ -130,4 +176,20 @@ public LegalEntityHandler getLegalEntityHandler() {
public void setLegalEntityHandler(LegalEntityHandler legalEntityHandler) {
this.legalEntityHandler = legalEntityHandler;
}
+
+ public RestClient getRestClient() {
+ return restClient;
+ }
+
+ public void setRestClient(RestClient restClient) {
+ this.restClient = restClient;
+ }
+
+ public ApplicationProperty getApplicationProperty() {
+ return applicationProperty;
+ }
+
+ public void setApplicationProperty(ApplicationProperty applicationProperty) {
+ this.applicationProperty = applicationProperty;
+ }
}
diff --git a/src/main/java/com/adyen/model/PolicyResource.java b/src/main/java/com/adyen/model/PolicyResource.java
new file mode 100644
index 0000000..ad9cca3
--- /dev/null
+++ b/src/main/java/com/adyen/model/PolicyResource.java
@@ -0,0 +1,36 @@
+package com.adyen.model;
+
+import java.util.List;
+
+public class PolicyResource {
+
+ private String accountHolderId;
+ private String type;
+
+ public String getAccountHolderId() {
+ return accountHolderId;
+ }
+
+ public void setAccountHolderId(String accountHolderId) {
+ this.accountHolderId = accountHolderId;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public PolicyResource accountHolderId(String accountHolderId) {
+ this.accountHolderId = accountHolderId;
+ return this;
+ }
+
+ public PolicyResource type(String type) {
+ this.type = type;
+ return this;
+ }
+
+}
diff --git a/src/main/java/com/adyen/model/SessionRequest.java b/src/main/java/com/adyen/model/SessionRequest.java
new file mode 100644
index 0000000..bf6b4e8
--- /dev/null
+++ b/src/main/java/com/adyen/model/SessionRequest.java
@@ -0,0 +1,50 @@
+package com.adyen.model;
+
+import java.security.Policy;
+
+public class SessionRequest {
+
+ private String allowOrigin;
+ private String product;
+ private SessionRequestPolicy policy;
+
+ public String getAllowOrigin() {
+ return allowOrigin;
+ }
+
+ public void setAllowOrigin(String allowOrigin) {
+ this.allowOrigin = allowOrigin;
+ }
+
+ public String getProduct() {
+ return product;
+ }
+
+ public void setProduct(String product) {
+ this.product = product;
+ }
+
+ public SessionRequestPolicy getPolicy() {
+ return policy;
+ }
+
+ public void setPolicy(SessionRequestPolicy policy) {
+ this.policy = policy;
+ }
+
+ public SessionRequest allowOrigin(String allowOrigin) {
+ this.allowOrigin = allowOrigin;
+ return this;
+ }
+
+ public SessionRequest product(String product) {
+ this.product = product;
+ return this;
+ }
+
+ public SessionRequest policy(SessionRequestPolicy policy) {
+ this.policy = policy;
+ return this;
+ }
+
+}
diff --git a/src/main/java/com/adyen/model/SessionRequestPolicy.java b/src/main/java/com/adyen/model/SessionRequestPolicy.java
new file mode 100644
index 0000000..f8a1d9d
--- /dev/null
+++ b/src/main/java/com/adyen/model/SessionRequestPolicy.java
@@ -0,0 +1,36 @@
+package com.adyen.model;
+
+import java.util.List;
+
+public class SessionRequestPolicy {
+
+ private List resources;
+ private List roles;
+
+ public List getResources() {
+ return resources;
+ }
+
+ public void setResources(List resources) {
+ this.resources = resources;
+ }
+
+ public List getRoles() {
+ return roles;
+ }
+
+ public void setRoles(List roles) {
+ this.roles = roles;
+ }
+
+ public SessionRequestPolicy resources(List resources) {
+ this.resources = resources;
+ return this;
+ }
+
+ public SessionRequestPolicy roles(List roles) {
+ this.roles = roles;
+ return this;
+ }
+
+}
diff --git a/src/main/java/com/adyen/model/SessionResponse.java b/src/main/java/com/adyen/model/SessionResponse.java
new file mode 100644
index 0000000..baa178c
--- /dev/null
+++ b/src/main/java/com/adyen/model/SessionResponse.java
@@ -0,0 +1,23 @@
+package com.adyen.model;
+
+public class SessionResponse {
+
+ private String id;
+ private String token;
+
+ public String getId() {
+ return id;
+ }
+
+ public void setId(String id) {
+ this.id = id;
+ }
+
+ public String getToken() {
+ return token;
+ }
+
+ public void setToken(String token) {
+ this.token = token;
+ }
+}
diff --git a/src/main/java/com/adyen/util/RestClient.java b/src/main/java/com/adyen/util/RestClient.java
new file mode 100644
index 0000000..4a9ffa0
--- /dev/null
+++ b/src/main/java/com/adyen/util/RestClient.java
@@ -0,0 +1,52 @@
+package com.adyen.util;
+
+import com.adyen.config.ApplicationProperty;
+import com.adyen.model.PolicyResource;
+import com.adyen.model.SessionRequest;
+import com.adyen.model.SessionRequestPolicy;
+import com.adyen.model.SessionResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.*;
+import org.springframework.stereotype.Service;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.List;
+
+@Service
+public class RestClient {
+
+ private final Logger log = LoggerFactory.getLogger(RestClient.class);
+
+ @Autowired
+ private ApplicationProperty applicationProperty;
+
+ public SessionResponse call(String url, SessionRequest payload) {
+
+ log.info("call {}", url);
+
+ RestTemplate restTemplate = new RestTemplate();
+
+ // Set headers
+ HttpHeaders headers = new HttpHeaders();
+ headers.setContentType(MediaType.APPLICATION_JSON);
+ headers.set("X-API-Key", this.getApplicationProperty().getBclApiKey());
+
+ HttpEntity entity = new HttpEntity<>(payload, headers);
+
+ // Perform the API request
+ ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, entity, SessionResponse.class);
+ log.info(response.toString());
+
+ return response.getBody();
+ }
+
+ public void setApplicationProperty(ApplicationProperty applicationProperty) {
+ this.applicationProperty = applicationProperty;
+ }
+
+ public ApplicationProperty getApplicationProperty() {
+ return applicationProperty;
+ }
+}