├── .env.default ├── .github └── stale.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── LICENSE ├── Procfile ├── README.md ├── app.json ├── package.json ├── screenshot.png ├── server ├── node │ ├── api │ │ ├── clientKeys.js │ │ ├── details.js │ │ ├── originKeys.js │ │ ├── paymentMethods.js │ │ ├── payments.js │ │ └── sessions.js │ ├── index.js │ └── utils │ │ ├── config.js │ │ ├── getPostParameters.js │ │ └── handleCallback.js └── php │ ├── api │ ├── clientKeys.php │ ├── details.php │ ├── originKeys.php │ ├── paymentMethods.php │ ├── payments.php │ └── sessions.php │ ├── index.php │ └── start.sh ├── src ├── ach │ ├── ach.js │ └── index.html ├── bancontact │ ├── bancontact.js │ └── index.html ├── bcmc │ ├── bcmc.js │ └── index.html ├── boleto │ ├── boleto.js │ └── index.html ├── card │ ├── card.js │ └── index.html ├── customcard │ ├── customCard.js │ ├── customCards.config.js │ ├── customcards.style.css │ └── index.html ├── demo.css ├── demo.js ├── dropin │ ├── dropin.js │ └── index.html ├── favicon.ico ├── googlepay │ ├── googlepay.js │ └── index.html ├── ideal │ ├── ideal.js │ └── index.html ├── index.html ├── multibanco │ ├── index.html │ └── multibanco.js ├── sepa │ ├── index.html │ └── sepa.js ├── sessions │ ├── dropin.js │ └── index.html ├── swish │ ├── index.html │ └── swish.js ├── utils.js └── wechatpay │ ├── index.html │ └── wechatpay.js └── start.sh /.env.default: -------------------------------------------------------------------------------- 1 | MERCHANT_ACCOUNT= 2 | CHECKOUT_APIKEY= 3 | CLIENT_KEY= 4 | API_VERSION= 5 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | # Number of days of inactivity before an Issue or Pull Request becomes stale 4 | daysUntilStale: 60 5 | 6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 7 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 8 | daysUntilClose: 7 9 | 10 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) 11 | # onlyLabels: [] 12 | 13 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 14 | exemptLabels: 15 | - pinned 16 | - security 17 | - "[Status] Maybe Later" 18 | 19 | # Set to true to ignore issues in a project (defaults to false) 20 | # exemptProjects: false 21 | 22 | # Set to true to ignore issues in a milestone (defaults to false) 23 | # exemptMilestones: false 24 | 25 | # Set to true to ignore issues with an assignee (defaults to false) 26 | # exemptAssignees: false 27 | 28 | # Label to use when marking as stale 29 | staleLabel: wontfix 30 | 31 | # Comment to post when marking as stale. Set to `false` to disable 32 | markComment: > 33 | This issue has been automatically marked as stale because it has not had 34 | recent activity. It will be closed if no further activity occurs. Thank you 35 | for your contributions. 36 | 37 | # Comment to post when removing the stale label. 38 | # unmarkComment: > 39 | # Your comment here. 40 | 41 | # Comment to post when closing a stale Issue or Pull Request. 42 | # closeComment: > 43 | # Your comment here. 44 | 45 | # Limit the number of actions per hour, from 1-30. Default is 30 46 | limitPerRun: 30 47 | 48 | # Limit to only `issues` or `pulls` 49 | # only: issues 50 | 51 | # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': 52 | # pulls: 53 | # daysUntilStale: 30 54 | # markComment: > 55 | # This pull request has been automatically marked as stale because it has not had 56 | # recent activity. It will be closed if no further activity occurs. Thank you 57 | # for your contributions. 58 | 59 | # issues: 60 | # exemptLabels: 61 | # - confirmed 62 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | .DS_Store 3 | .env 4 | *.log 5 | coverage 6 | logs 7 | node_modules/ 8 | npm-debug.log* 9 | package-lock.json 10 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at support@adyen.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) Adyen B.V. (https://www.adyen.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: node server/node 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Adyen Web sample code 2 | 3 | ![Adyen Web Sample Code](screenshot.png) 4 | 5 | > ⚠️ **This repository is for demo purposes only** 6 | 7 | ## Requirements 8 | 9 | To run this project, **create** a `.env` file on your project's root folder following the example on `.env.default`. 10 | 11 | ``` 12 | MERCHANT_ACCOUNT=MyMerchantAccount 13 | CHECKOUT_APIKEY=MY_CHECKOUT_API_KEY 14 | CLIENT_KEY=MY_CLIENT_KEY 15 | ``` 16 | 17 | These variables can be found in Adyen Customer Area. For more information, visit our [Get started with Adyen guide](https://docs.adyen.com/get-started-with-adyen#page-introduction). 18 | 19 | If the forms don't seem to load, please check if you have: 20 | 21 | 1. Used the correct `clientKey` 22 | 2. Configured the `origin` on the Customer Area as an allowed origin 23 | 24 | ## Installation 25 | 26 | ### Running the PHP Server 27 | 28 | Navigate to the root of the project and run the `start.sh` script: 29 | 30 | ``` 31 | $ cd adyen-components-js-sample-code 32 | $ ./start.sh 33 | ``` 34 | 35 | A PHP server will start on `http://localhost:3000`. 36 | 37 | ### Running the Node.js Server 38 | 39 | If preferred, you can run a Node.js server instead. 40 | To do this, navigate to the root of the project, install the dependencies (only the first time) and run the start script: 41 | 42 | ``` 43 | $ cd adyen-components-js-sample-code 44 | $ npm i 45 | $ npm start 46 | ``` 47 | 48 | A Node.js server will start on `http://localhost:3000`. 49 | 50 | ### Deploying this example to Heroku 51 | 52 | Alternatively, you can install this example by using this shortcut to deploy to Heroku: 53 | 54 | [![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Adyen/adyen-components-js-sample-code) 55 | 56 | After deploying, to use Sessions Drop-in, add your ```CLIENT_KEY``` to the config vars. 57 | 58 | ## Documentation 59 | 60 | For the complete integration guide, refer to the [Web Components documentation](https://docs.adyen.com/online-payments/web-components). 61 | 62 | ## Other sample projects 63 | 64 | Find other sample projects in our [example projects repositories](https://github.com/adyen-examples). 65 | 66 | ## License 67 | 68 | This repository is open source and available under the MIT license. For more information, see the LICENSE file. 69 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Adyen Components Sample Code", 3 | "description": "A php server example containing our Javascript SDK", 4 | "keywords": [ 5 | "Adyen", 6 | "Checkout", 7 | "Components", 8 | "Dropin", 9 | "Web", 10 | "JavaScript", 11 | "payments" 12 | ], 13 | "website": "https://www.adyen.com/", 14 | "repository": "https://github.com/Adyen/adyen-components-js-sample-code", 15 | "env": { 16 | "MERCHANT_ACCOUNT": { 17 | "description": "Your merchant account" 18 | }, 19 | "CHECKOUT_APIKEY": { 20 | "description": "Your Checkout API key" 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "checkout-components-sample-code", 3 | "version": "1.0.0", 4 | "description": "Adyen Components Sample Code", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "start": "npm run devserver", 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "devserver": "node ./server/node/index.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "" 14 | }, 15 | "keywords": [ 16 | "Adyen", 17 | "Demo", 18 | "Payments", 19 | "Checkout", 20 | "Components", 21 | "Dropin" 22 | ], 23 | "author": "Adyen", 24 | "license": "MIT", 25 | "engines": { 26 | "node": "~8.11.2", 27 | "npm": "~6.1.0" 28 | }, 29 | "dependencies": { 30 | "dotenv": "^6.1.0", 31 | "express": "^4.16.4", 32 | "request": "^2.81.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adyen/adyen-components-js-sample-code/dd5a2925f714f636ebf80d2ea6224a62ce22b286/screenshot.png -------------------------------------------------------------------------------- /server/node/api/clientKeys.js: -------------------------------------------------------------------------------- 1 | const { CLIENT_KEY: clientKey } = require('../utils/config'); 2 | const handleCallback = require('../utils/handleCallback'); 3 | 4 | module.exports = (res, request) => { 5 | handleCallback({ body: { clientKey } }, res); 6 | }; 7 | -------------------------------------------------------------------------------- /server/node/api/details.js: -------------------------------------------------------------------------------- 1 | const { post } = require('request'); 2 | const getPostParameters = require('../utils/getPostParameters'); 3 | const handleCallback = require('../utils/handleCallback'); 4 | 5 | module.exports = (res, request) => { 6 | const params = getPostParameters('/payments/details', { ...request }); 7 | 8 | post(params, (err, response, body) => handleCallback({ err, response, body }, res)); 9 | }; 10 | -------------------------------------------------------------------------------- /server/node/api/originKeys.js: -------------------------------------------------------------------------------- 1 | const { post } = require('request'); 2 | const { MERCHANT_ACCOUNT } = require('../utils/config'); 3 | const getPostParameters = require('../utils/getPostParameters'); 4 | const handleCallback = require('../utils/handleCallback'); 5 | 6 | module.exports = (res, request) => { 7 | const originDomains = [`${request.protocol}://${request.headers.host}`]; 8 | const params = getPostParameters('originKeys', { originDomains }); 9 | 10 | post(params, (err, response, body) => handleCallback({ err, response, body }, res)); 11 | }; 12 | -------------------------------------------------------------------------------- /server/node/api/paymentMethods.js: -------------------------------------------------------------------------------- 1 | const { post } = require('request'); 2 | const getPostParameters = require('../utils/getPostParameters'); 3 | const handleCallback = require('../utils/handleCallback'); 4 | 5 | module.exports = (res, request) => { 6 | const params = getPostParameters('paymentMethods', request); 7 | 8 | post(params, (error, response, body) => handleCallback({ error, response, body }, res)); 9 | }; 10 | -------------------------------------------------------------------------------- /server/node/api/payments.js: -------------------------------------------------------------------------------- 1 | const { post } = require('request'); 2 | const getPostParameters = require('../utils/getPostParameters'); 3 | const handleCallback = require('../utils/handleCallback'); 4 | 5 | module.exports = (res, request) => { 6 | const params = getPostParameters('/payments', request); 7 | 8 | post(params, (err, response, body) => handleCallback({ err, response, body }, res)); 9 | }; 10 | -------------------------------------------------------------------------------- /server/node/api/sessions.js: -------------------------------------------------------------------------------- 1 | const { post } = require('request'); 2 | const getPostParameters = require('../utils/getPostParameters'); 3 | const handleCallback = require('../utils/handleCallback'); 4 | 5 | module.exports = (res, request) => { 6 | const params = getPostParameters('/sessions', request); 7 | 8 | post(params, (err, response, body) => handleCallback({ err, response, body }, res)); 9 | }; 10 | -------------------------------------------------------------------------------- /server/node/index.js: -------------------------------------------------------------------------------- 1 | require('dotenv').config(); 2 | const express = require('express'); 3 | const app = express(); 4 | const path = require('path'); 5 | const getPaymentMethods = require('./api/paymentMethods'); 6 | const getOriginKeys = require('./api/originKeys'); 7 | const getClientKeys = require('./api/clientKeys'); 8 | const makePayment = require('./api/payments'); 9 | const postDetails = require('./api/details'); 10 | const sessions = require('./api/sessions'); 11 | 12 | module.exports = (() => { 13 | app.use(express.json()); 14 | app.use(express.urlencoded({ extended: true })); 15 | 16 | app.use((req, res, next) => { 17 | res.header('Access-Control-Allow-Origin', '*'); 18 | res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept'); 19 | next(); 20 | }); 21 | 22 | app.use(express.static(path.resolve(__dirname, '../../src'))); 23 | 24 | app.all('/originKeys', (req, res) => getOriginKeys(res, req)); 25 | app.all('/paymentMethods', (req, res) => getPaymentMethods(res, req.body)); 26 | app.all('/payments', (req, res) => makePayment(res, req.body)); 27 | app.all('/details', (req, res) => postDetails(res, req.body)); 28 | app.all('/sessions', (req, res) => sessions(res, req.body)); 29 | app.all('/clientKeys', (req, res) => getClientKeys(res, req)); 30 | 31 | const port = process.env.PORT || 3000; 32 | app.listen(port, () => console.log(`Listening on localhost:${port}`)); 33 | })(); 34 | -------------------------------------------------------------------------------- /server/node/utils/config.js: -------------------------------------------------------------------------------- 1 | const { CHECKOUT_APIKEY, MERCHANT_ACCOUNT, CLIENT_KEY, API_VERSION } = process.env; 2 | 3 | const CHECKOUT_URL = `https://checkout-test.adyen.com/${API_VERSION}`; 4 | 5 | module.exports = { 6 | CHECKOUT_APIKEY, 7 | CHECKOUT_URL, 8 | MERCHANT_ACCOUNT, 9 | CLIENT_KEY 10 | }; 11 | -------------------------------------------------------------------------------- /server/node/utils/getPostParameters.js: -------------------------------------------------------------------------------- 1 | const { CHECKOUT_APIKEY, CHECKOUT_URL, MERCHANT_ACCOUNT } = require('./config'); 2 | 3 | module.exports = (endpoint, request) => { 4 | const body = JSON.stringify({ 5 | merchantAccount: MERCHANT_ACCOUNT, 6 | ...request 7 | }); 8 | 9 | console.log('### getPostParameters::exports:: CHECKOUT_URL=', `${CHECKOUT_URL}/${endpoint}`); 10 | 11 | return { 12 | body, 13 | url: `${CHECKOUT_URL}/${endpoint}`, 14 | headers: { 15 | 'Access-Control-Allow-Origin': '*', 16 | 'Content-Type': 'application/json', 17 | 'Content-Length': Buffer.byteLength(body, 'utf8'), 18 | 'X-Api-Key': CHECKOUT_APIKEY 19 | } 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /server/node/utils/handleCallback.js: -------------------------------------------------------------------------------- 1 | module.exports = ({ error, response = {}, body }, res) => { 2 | if (error) { 3 | console.error(error); 4 | return res.send(error); 5 | } 6 | 7 | if (response.statusCode && response.statusMessage) { 8 | console.log(`Request to ${res.req.url} ended with status ${response.statusCode} - ${response.statusMessage}`); 9 | } 10 | 11 | res.send(body); 12 | }; 13 | -------------------------------------------------------------------------------- /server/php/api/clientKeys.php: -------------------------------------------------------------------------------- 1 | $clientKey 12 | ]; 13 | 14 | $result = json_encode($data); 15 | 16 | return $result; 17 | } 18 | -------------------------------------------------------------------------------- /server/php/api/details.php: -------------------------------------------------------------------------------- 1 | $merchantAccount 24 | ]; 25 | 26 | // Convert data to JSON 27 | $json_data = json_encode(array_merge($data, $request)); 28 | 29 | // Initiate curl 30 | $curlAPICall = curl_init(); 31 | 32 | // Set to POST 33 | curl_setopt($curlAPICall, CURLOPT_CUSTOMREQUEST, "POST"); 34 | 35 | // Will return the response, if false it print the response 36 | curl_setopt($curlAPICall, CURLOPT_RETURNTRANSFER, true); 37 | 38 | // Add JSON message 39 | curl_setopt($curlAPICall, CURLOPT_POSTFIELDS, $json_data); 40 | 41 | // Set the url 42 | curl_setopt($curlAPICall, CURLOPT_URL, $url); 43 | 44 | // Api key 45 | curl_setopt($curlAPICall, CURLOPT_HTTPHEADER, 46 | array( 47 | "X-Api-Key: " . $apikey, 48 | "Content-Type: application/json", 49 | "Content-Length: " . strlen($json_data) 50 | ) 51 | ); 52 | 53 | // Execute 54 | $result = curl_exec($curlAPICall); 55 | 56 | // Error Check 57 | if ($result === false){ 58 | throw new Exception(curl_error($curlAPICall), curl_errno($curlAPICall)); 59 | } 60 | 61 | // Closing 62 | curl_close($curlAPICall); 63 | 64 | // This file returns a JSON object 65 | return $result; 66 | } 67 | -------------------------------------------------------------------------------- /server/php/api/originKeys.php: -------------------------------------------------------------------------------- 1 | [$protocol.$domain] 19 | ]; 20 | 21 | // Convert data to JSON 22 | $json_data = json_encode($data); 23 | 24 | // Initiate curl 25 | $curlAPICall = curl_init(); 26 | 27 | // Set to POST 28 | curl_setopt($curlAPICall, CURLOPT_CUSTOMREQUEST, "POST"); 29 | 30 | // Will return the response, if false it print the response 31 | curl_setopt($curlAPICall, CURLOPT_RETURNTRANSFER, true); 32 | 33 | // Add JSON message 34 | curl_setopt($curlAPICall, CURLOPT_POSTFIELDS, $json_data); 35 | 36 | // Set the url 37 | curl_setopt($curlAPICall, CURLOPT_URL, $url); 38 | 39 | // Api key 40 | curl_setopt($curlAPICall, CURLOPT_HTTPHEADER, 41 | array( 42 | "X-Api-Key: " . $apikey, 43 | "Content-Type: application/json", 44 | "Content-Length: " . strlen($json_data) 45 | ) 46 | ); 47 | 48 | // Execute 49 | $result = curl_exec($curlAPICall); 50 | 51 | // Error Check 52 | if ($result === false){ 53 | throw new Exception(curl_error($curlAPICall), curl_errno($curlAPICall)); 54 | } 55 | 56 | // Closing 57 | curl_close($curlAPICall); 58 | 59 | // This file returns a JSON object 60 | return $result; 61 | } 62 | -------------------------------------------------------------------------------- /server/php/api/paymentMethods.php: -------------------------------------------------------------------------------- 1 | $merchantAccount 25 | ]; 26 | 27 | // Convert data to JSON 28 | $json_data = json_encode(array_merge($data, $request)); 29 | 30 | // Initiate curl 31 | $curlAPICall = curl_init(); 32 | 33 | // Set to POST 34 | curl_setopt($curlAPICall, CURLOPT_CUSTOMREQUEST, "POST"); 35 | 36 | // Will return the response, if false it print the response 37 | curl_setopt($curlAPICall, CURLOPT_RETURNTRANSFER, true); 38 | 39 | // Add JSON message 40 | curl_setopt($curlAPICall, CURLOPT_POSTFIELDS, $json_data); 41 | 42 | // Set the url 43 | curl_setopt($curlAPICall, CURLOPT_URL, $url); 44 | 45 | // Api key 46 | curl_setopt($curlAPICall, CURLOPT_HTTPHEADER, 47 | array( 48 | "X-Api-Key: " . $apikey, 49 | "Content-Type: application/json", 50 | "Content-Length: " . strlen($json_data) 51 | ) 52 | ); 53 | 54 | // Execute 55 | $result = curl_exec($curlAPICall); 56 | 57 | // Error Check 58 | if ($result === false){ 59 | throw new Exception(curl_error($curlAPICall), curl_errno($curlAPICall)); 60 | } 61 | 62 | // Closing 63 | curl_close($curlAPICall); 64 | 65 | // This file returns a JSON object 66 | return $result; 67 | } 68 | -------------------------------------------------------------------------------- /server/php/api/payments.php: -------------------------------------------------------------------------------- 1 | [ 24 | 'currency' => 'EUR', 25 | 'value' => 1000 26 | ], 27 | 'reference' => 'Order Reference', 28 | 'returnUrl' => 'https://your-company.com/...', 29 | 'merchantAccount' => $merchantAccount 30 | ]; 31 | 32 | // Convert data to JSON 33 | $json_data = json_encode(array_merge($data, $request)); 34 | 35 | // Initiate curl 36 | $curlAPICall = curl_init(); 37 | 38 | // Set to POST 39 | curl_setopt($curlAPICall, CURLOPT_CUSTOMREQUEST, "POST"); 40 | 41 | // Will return the response, if false it print the response 42 | curl_setopt($curlAPICall, CURLOPT_RETURNTRANSFER, true); 43 | 44 | // Add JSON message 45 | curl_setopt($curlAPICall, CURLOPT_POSTFIELDS, $json_data); 46 | 47 | // Set the url 48 | curl_setopt($curlAPICall, CURLOPT_URL, $url); 49 | 50 | // Api key 51 | curl_setopt($curlAPICall, CURLOPT_HTTPHEADER, 52 | array( 53 | "X-Api-Key: " . $apikey, 54 | "Content-Type: application/json", 55 | "Content-Length: " . strlen($json_data) 56 | ) 57 | ); 58 | 59 | // Execute 60 | $result = curl_exec($curlAPICall); 61 | 62 | // Error Check 63 | if ($result === false){ 64 | throw new Exception(curl_error($curlAPICall), curl_errno($curlAPICall)); 65 | } 66 | 67 | // Closing 68 | curl_close($curlAPICall); 69 | 70 | // This file returns a JSON object 71 | return $result; 72 | } 73 | -------------------------------------------------------------------------------- /server/php/api/sessions.php: -------------------------------------------------------------------------------- 1 | [ 24 | 'currency' => 'EUR', 25 | 'value' => 1000 26 | ], 27 | 'reference' => 'Order Reference', 28 | 'returnUrl' => 'https://your-company.com/...', 29 | 'merchantAccount' => $merchantAccount 30 | ]; 31 | 32 | // Convert data to JSON 33 | $json_data = json_encode(array_merge($data, $request)); 34 | 35 | // Initiate curl 36 | $curlAPICall = curl_init(); 37 | 38 | // Set to POST 39 | curl_setopt($curlAPICall, CURLOPT_CUSTOMREQUEST, "POST"); 40 | 41 | // Will return the response, if false it print the response 42 | curl_setopt($curlAPICall, CURLOPT_RETURNTRANSFER, true); 43 | 44 | // Add JSON message 45 | curl_setopt($curlAPICall, CURLOPT_POSTFIELDS, $json_data); 46 | 47 | // Set the url 48 | curl_setopt($curlAPICall, CURLOPT_URL, $url); 49 | 50 | // Api key 51 | curl_setopt($curlAPICall, CURLOPT_HTTPHEADER, 52 | array( 53 | "X-Api-Key: " . $apikey, 54 | "Content-Type: application/json", 55 | "Content-Length: " . strlen($json_data) 56 | ) 57 | ); 58 | 59 | // Execute 60 | $result = curl_exec($curlAPICall); 61 | 62 | // Error Check 63 | if ($result === false){ 64 | throw new Exception(curl_error($curlAPICall), curl_errno($curlAPICall)); 65 | } 66 | 67 | // Closing 68 | curl_close($curlAPICall); 69 | 70 | // This file returns a JSON object 71 | return $result; 72 | } 73 | -------------------------------------------------------------------------------- /server/php/index.php: -------------------------------------------------------------------------------- 1 | { 3 | 4 | // Optional, provide a translations object for labels and fields 5 | // const translations = { 6 | // "en-GB": { 7 | // "ach.bankAccount": "Bank account", 8 | // "ach.accountHolderNameField.title": "Account holder name", 9 | // "ach.accountHolderNameField.placeholder": "J. Smith", 10 | // } 11 | // }; 12 | 13 | // 1. Create an instance of AdyenCheckout 14 | const checkout = await AdyenCheckout({ 15 | locale: "en-GB", 16 | environment: 'test', 17 | // Optional, provide translations for labels and fields 18 | // https://docs.adyen.com/online-payments/web-components/localization-components 19 | // translations: translations, 20 | clientKey: clientKey, // Mandatory. clientKey from Customer Area 21 | }); 22 | 23 | // 2. Create and mount the Component 24 | const ach = checkout 25 | .create('ach', { 26 | // Optional Configuration 27 | // hasHolderName: false, // Defaults to true 28 | 29 | // Optional. Customize the look and feel of the payment form 30 | // https://docs.adyen.com/developers/checkout/api-integration/configure-secured-fields/styling-secured-fields 31 | styles: {}, 32 | 33 | // Optionally show a Pay Button 34 | showPayButton: true, 35 | 36 | // Events 37 | onSubmit: (state, component) => { 38 | if (state.isValid) { 39 | // ACH only works in US or PR, with payment in USD 40 | const additionalConfig = { 41 | countryCode: state.data.billingAddress.country, 42 | amount: { 43 | value: 1000, 44 | currency: 'USD' 45 | } 46 | } 47 | makePayment(ach.data, additionalConfig); 48 | } 49 | }, 50 | 51 | onChange: (state, component) => { 52 | // state.data; 53 | // state.isValid; 54 | updateStateContainer(state); // Demo purposes only 55 | }, 56 | 57 | // Optional: insert address information, if you already have it 58 | // data: { 59 | // holderName: 'B. Fish', 60 | // billingAddress: { 61 | // street: 'Infinite Loop', 62 | // postalCode: '95014', 63 | // city: 'Cupertino', 64 | // houseNumberOrName: '1', 65 | // country: 'US', 66 | // stateOrProvince: 'CA' 67 | // } 68 | // } 69 | }) 70 | .mount('#ach-container'); 71 | }); -------------------------------------------------------------------------------- /src/ach/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | Back 16 | 17 |

ACH Component

18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 |
26 |

27 | Check the Source Code to see the full implementation. 28 |

29 |

30 | To make a payment, use a valid ABA routing number: bank routing numbers. 31 |

32 |

33 | For more information, please refer to the Checkout Components documentation. 34 |

35 |
36 |
37 | 38 | 76 |
77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /src/bancontact/bancontact.js: -------------------------------------------------------------------------------- 1 | // 0. Get clientKey 2 | getClientKey().then(async clientKey => { 3 | // 1. Create an instance of AdyenCheckout providing the clientKey 4 | const checkout = await AdyenCheckout({ 5 | clientKey: clientKey, // Mandatory. clientKey from Customer Area 6 | environment: 'test', 7 | amount: { 8 | currency: 'EUR', 9 | value: 1000 10 | }, // amount to be shown next to the qrcode 11 | onAdditionalDetails: result => { 12 | console.log(result); 13 | }, 14 | onError: error => { 15 | console.log(error); 16 | } 17 | }); 18 | 19 | // Override our default demo config for this payment method 20 | const bancontactData = { 21 | countryCode: 'BE', 22 | amount: { 23 | value: 1000, 24 | currency: 'EUR' 25 | }, 26 | paymentMethod: { 27 | type: 'bcmc_mobile_QR' 28 | } 29 | }; 30 | 31 | /** Call the /payments endpoint to retrieve the necessary data to start the Bancontact component 32 | * We need the following parts of the response 33 | * - qrCodeData (redirect.data.qrCodeData): The data the QR Code will contain 34 | * - paymentData Necessary to communicate with Adyen to check the current payment status 35 | */ 36 | makePayment(bancontactData).then(response => { 37 | if (!!response.action) { 38 | // 2. Create and mount the Component 39 | const bancontact = checkout.createFromAction(response.action).mount('#bancontact-container'); 40 | } 41 | }); 42 | }); -------------------------------------------------------------------------------- /src/bancontact/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | Back 16 | 17 |

Bancontact Mobile Component

18 |
19 | 20 |
21 | 22 |
23 |
24 |
25 |
26 |

27 | Check the Source Code to see the full implementation. 28 |

29 |

30 | For more information, please refer to the Checkout Components documentation. 31 |

32 |
33 |
34 | 35 | 65 |
66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/bcmc/bcmc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * IMPORTANT - Set a boolean indicating whether index.html is loading a version of adyen.js (& adyen.css) >= 5.0.0 3 | */ 4 | const head = document.head.innerHTML; 5 | const version = head.substring(head.indexOf('sdk/') + 4, head.indexOf('/adyen')); 6 | const majorVn = Number(version.substring(0, version.indexOf('.'))); 7 | const IS_VERSION_5 = majorVn >= 5; 8 | 9 | // 0. Get client key 10 | getClientKey().then(async clientKey => { 11 | 12 | // 1. Create an instance of AdyenCheckout providing the clientKey 13 | const configObj = { 14 | clientKey: clientKey, 15 | environment: 'test', 16 | amount: { 17 | currency: 'EUR', 18 | value: 1000 19 | }, 20 | showPayButton: true, 21 | onSubmit: (state, component) => { 22 | makePayment(state.data); 23 | } 24 | } 25 | 26 | if (!IS_VERSION_5) { 27 | window.checkout = new AdyenCheckout(configObj); 28 | } else { 29 | window.checkout = await AdyenCheckout(configObj); 30 | } 31 | 32 | // 2. Create and mount component. 33 | checkout.create('bcmc').mount('#bcmc-container'); 34 | }); -------------------------------------------------------------------------------- /src/bcmc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | Back 16 | 17 |

Bancontact Card Component

18 |
19 | 20 |
21 | 22 |
23 |
24 |
25 |
26 |

27 | Check the Source Code to see the full implementation. 28 |

29 |

30 | For more information, please refer to the Checkout Components documentation. 31 |

32 |
33 |
34 | 35 | 64 |
65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/boleto/boleto.js: -------------------------------------------------------------------------------- 1 | // 1. Create an instance of AdyenCheckout 2 | 3 | async function initiateComponent() { 4 | const checkout = await AdyenCheckout({ 5 | environment: 'test', 6 | showPayButton: true, 7 | onSubmit: (state, component) => { 8 | makePayment(state.data); 9 | }, 10 | onChange: (state, component) => { 11 | // state.data; 12 | // state.isValid; 13 | 14 | updateStateContainer(state); // Demo purposes only 15 | } 16 | }); 17 | // 2. Create and mount the Component 18 | const boleto = checkout.create('boletobancario').mount('#boletobancario-container'); 19 | 20 | // This is a mock of the /payments response action property 21 | const actionMock = { 22 | downloadUrl: 'https://...', 23 | expiresAt: '2022-09-11T00:00:00', 24 | initialAmount: { 25 | currency: 'BRL', 26 | value: 1000 27 | }, 28 | paymentMethodType: 'boletobancario', 29 | reference: '12345.12345 12345.123456 12345.123456 1 12345678901', 30 | totalAmount: { 31 | currency: 'BRL', 32 | value: 1000 33 | }, 34 | type: 'voucher' 35 | }; 36 | 37 | // 3. Get the action property from the /payments response and use it to render the voucher 38 | const boletoVoucher = checkout.createFromAction(actionMock).mount('#boletobancario-result-container'); 39 | } 40 | initiateComponent() -------------------------------------------------------------------------------- /src/boleto/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 |
13 |
14 | Back 15 | 16 |
17 |

Boleto Bancario Component

18 |

Shopper Details Form

19 |
20 |
21 | 22 |
23 |
24 | 25 |

Payment Result (Voucher)

26 |
27 |
28 | 29 |
30 |
31 |
32 | 33 |
34 |

35 | Check the Source Code to see the full implementation. 36 |

37 |

38 | For more information, please refer to the Checkout Components documentation. 39 |

40 |
41 |
42 | 43 | 80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /src/card/card.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Handling redirect results 4 | */ 5 | function handleRedirectResult() { 6 | const { redirectResult } = getSearchParameters(window.location.search); 7 | 8 | console.log('### card::handleRedirectResult:: redirectResult', redirectResult); 9 | 10 | if (redirectResult) { 11 | // Makes call to /payments/details 12 | return handleAdditionalDetails({ 13 | data: { 14 | details: { 15 | redirectResult 16 | } 17 | } 18 | }) 19 | } 20 | 21 | return false; 22 | } 23 | 24 | handleRedirectResult(); 25 | 26 | /** 27 | * IMPORTANT - Set a boolean indicating whether index.html is loading a version of adyen.js (& adyen.css) >= 5.0.0 28 | */ 29 | const head = document.head.innerHTML; 30 | const version = head.substring(head.indexOf('sdk/') + 4, head.indexOf('/adyen')); 31 | const majorVn = Number(version.substring(0, version.indexOf('.'))); 32 | const IS_VERSION_5 = majorVn >= 5; 33 | 34 | // 0. Get clientKey 35 | Promise.all([ getClientKey(), getPaymentMethods()]).then(async response => { 36 | 37 | // Optional, define custom placeholders for the Card fields 38 | // https://docs.adyen.com/online-payments/web-components/localization-components 39 | // const translations = { 40 | // "en-GB": { 41 | // "creditCard.numberField.placeholder": "1234 5678 9012 3456", 42 | // "creditCard.expiryDateField.placeholder": "MM/YY", 43 | // } 44 | // }; 45 | 46 | const configObj = { 47 | environment: 'test', 48 | locale: "en-GB", 49 | // translations: translations, 50 | clientKey: response[0], 51 | paymentMethodsResponse: response[1], 52 | // Events 53 | onSubmit: (state, component) => { 54 | if (state.isValid) { 55 | 56 | const config = { 57 | additionalData: {allow3DS2: true}, // allows regular, "in app", 3DS2 58 | } 59 | 60 | const cardData = {...card.data} 61 | 62 | makePayment(cardData, config).then(response => { 63 | if (response.action) { 64 | component.handleAction(response.action); 65 | // checkout.createFromAction(response.action, { challengeWindowSize: '01' }).mount('#card-container') 66 | console.log('### handlers::handleResponse::response.action=', response.action); 67 | } 68 | }); 69 | } 70 | }, 71 | 72 | onChange: (state, component) => { 73 | // state.data; 74 | // state.isValid; 75 | 76 | updateStateContainer(state); // Demo purposes only 77 | }, 78 | onAdditionalDetails: (details) => { 79 | console.log('### card::onAdditionalDetails:: calling' ); 80 | handleAdditionalDetails(details).then(response => { 81 | console.log('### card::onAdditionalDetails:: response', response); 82 | }); 83 | }, 84 | 85 | onError: (e)=>{ 86 | console.log('### Checkout config onError:: e=', e); 87 | } 88 | } 89 | 90 | // 1. Create an instance of AdyenCheckout 91 | if (!IS_VERSION_5) { 92 | window.checkout = new AdyenCheckout(configObj); 93 | } else { 94 | window.checkout = await AdyenCheckout(configObj); 95 | } 96 | 97 | // 2. Create and mount the Component 98 | window.card = checkout 99 | .create('card', { 100 | // Optional Configuration 101 | // hasHolderName: true, 102 | // holderNameRequired: true, 103 | 104 | // Optional. Customize the look and feel of the payment form 105 | // https://docs.adyen.com/developers/checkout/api-integration/configure-secured-fields/styling-secured-fields 106 | styles: {}, 107 | 108 | // Optionally show a Pay Button 109 | showPayButton: true, 110 | enableStoreDetails: true, 111 | 112 | _disableClickToPay: true, 113 | 114 | onBinLookup: (obj)=>{ 115 | console.log('### Card config::onBinLookup:: obj=', obj); 116 | }, 117 | onFocus: (obj) => { 118 | console.log('### Cards::onFocus:: obj',obj); 119 | }, 120 | onBlur: (obj) => { 121 | console.log('### Cards::onBlur:: obj',obj); 122 | } 123 | }) 124 | .mount('#card-container'); 125 | }); -------------------------------------------------------------------------------- /src/card/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 | Back 17 | 18 |

Card Component

19 |
20 |
21 | 22 |
23 |
24 |
25 | 26 |
27 |

28 | Check the Source Code to see the full implementation. 29 |

30 |

31 | To make a payment, use our test card numbers. 32 |

33 |

34 | For more information, please refer to the Checkout Components documentation. 35 |

36 |
37 |
38 | 39 | 78 |
79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /src/customcard/customCard.js: -------------------------------------------------------------------------------- 1 | import {setFocus, onBrand, onConfigSuccess, onBinLookup, setCCErrors, onChange, onChangeV5} from './customCards.config.js'; 2 | 3 | /** 4 | * IMPORTANT - Set a boolean indicating whether index.html is loading a version of adyen.js (& adyen.css) >= 5.0.0 5 | */ 6 | const head = document.head.innerHTML; 7 | const version = head.substring(head.indexOf('sdk/') + 4, head.indexOf('/adyen')); 8 | const majorVn = Number(version.substring(0, version.indexOf('.'))); 9 | const IS_VERSION_5 = majorVn >= 5; 10 | 11 | //const mockPaymentMethodsResponse = { 12 | // paymentMethods: [ 13 | // { 14 | // brands: ['mc', 'visa', 'amex', 'maestro', 'cup', 'diners', 'discover', 'jcb', 'bijcard'], 15 | // name: 'Credit Card', 16 | // type: 'scheme' 17 | // } 18 | // ] 19 | //} 20 | 21 | // 0. Get clientKey 22 | getClientKey().then(async clientKey => { 23 | 24 | const configObj = { 25 | clientKey : clientKey, 26 | environment : 'test', 27 | locale : 'en-US', 28 | // paymentMethodsResponse: mockPaymentMethodsResponse 29 | } 30 | 31 | // 1. Create an instance of AdyenCheckout 32 | if (!IS_VERSION_5) { 33 | window.checkout = new AdyenCheckout(configObj); 34 | } else { 35 | window.checkout = await AdyenCheckout(configObj); 36 | } 37 | 38 | window.securedFields = checkout 39 | .create('securedfields', { 40 | type: 'card', 41 | brands : ['mc', 'visa', 'amex', 'bcmc', 'maestro', 'cartebancaire'], 42 | onConfigSuccess, 43 | onBrand, 44 | onFocus : setFocus, 45 | onBinLookup, 46 | 47 | ...(!IS_VERSION_5 && {onError : setCCErrors}), // For version < 5.0.0 48 | 49 | onChange : (state, component) => { 50 | /** 51 | * For version < 5.0.0 52 | */ 53 | if (!IS_VERSION_5) { 54 | onChange(state, component); 55 | 56 | updateStateContainer(state);// Demo purposes only 57 | return; 58 | } 59 | 60 | /** 61 | * For version >= 5.0.0 62 | */ 63 | onChangeV5(state, component); 64 | 65 | // In v5, we enhance the securedFields state.errors object with a rootNode prop 66 | // but calling updateStateContainer with the ref to this rootNode element will cause a "Converting circular structure to JSON" error 67 | // so replace any rootNode values in the objects in state.errors with an empty string 68 | if (!!Object.keys(state.errors).length) { 69 | const nuErrors = Object.entries(state.errors).reduce((acc, [fieldType, error]) => { 70 | acc[fieldType] = error ? {...error, rootNode : ''} : error; 71 | return acc; 72 | }, {}); 73 | state.errors = nuErrors; 74 | } 75 | 76 | updateStateContainer(state);// Demo purposes only 77 | } 78 | }) 79 | .mount('#card-container'); 80 | 81 | createPayButton('#card-container', window.securedFields, 'securedfields'); 82 | 83 | function createPayButton(parent, component, attribute) { 84 | const payBtn = document.createElement('button'); 85 | 86 | payBtn.textContent = 'Pay'; 87 | payBtn.name = 'pay'; 88 | payBtn.classList.add('adyen-checkout__button', 'js-components-button--one-click', `js-${attribute}`); 89 | 90 | payBtn.addEventListener('click', e => { 91 | e.preventDefault(); 92 | 93 | if (!component.isValid) { 94 | return component.showValidation(); 95 | } 96 | 97 | makePayment(component.formatData()); 98 | 99 | payBtn.style.opacity = '0.5'; 100 | }); 101 | 102 | document.querySelector(parent).appendChild(payBtn); 103 | 104 | return payBtn; 105 | } 106 | }); 107 | 108 | -------------------------------------------------------------------------------- /src/customcard/customCards.config.js: -------------------------------------------------------------------------------- 1 | let hideCVC = false; 2 | let optionalCVC = false; 3 | let hideDate = false; 4 | let optionalDate = false; 5 | let isDualBranding = false; 6 | 7 | function setAttributes(el, attrs) { 8 | for (const key in attrs) { 9 | el.setAttribute(key, attrs[key]); 10 | } 11 | } 12 | 13 | function setLogosActive(rootNode, mode) { 14 | const imageHolder = rootNode.querySelector('.pm-image'); 15 | const dualBrandingImageHolder = rootNode.querySelector('.pm-image-dual'); 16 | 17 | switch (mode) { 18 | case 'dualBranding_notValid': 19 | Object.assign(imageHolder.style, { display: 'none' }); 20 | Object.assign(dualBrandingImageHolder.style, { display: 'block', 'pointer-events': 'none', opacity: 0.5 }); 21 | break; 22 | 23 | case 'dualBranding_valid': 24 | Object.assign(imageHolder.style, { display: 'none' }); 25 | Object.assign(dualBrandingImageHolder.style, { display: 'block', 'pointer-events': 'auto', opacity: 1 }); 26 | break; 27 | 28 | default: 29 | // reset 30 | Object.assign(imageHolder.style, { display: 'block' }); 31 | Object.assign(dualBrandingImageHolder.style, { display: 'none' }); 32 | } 33 | } 34 | 35 | // Can be imported by customCard and added to the config object used in checkout.create('securedfields') 36 | export const styles = { 37 | // base: { 38 | // caretColor: 'red' 39 | // }, 40 | error: { 41 | color: 'red' 42 | }, 43 | validated: { 44 | color: 'green', 45 | fontWeight: 'bold' 46 | // background: 'blue' 47 | }, 48 | placeholder: { 49 | color: '#d8d8d8' 50 | } 51 | }; 52 | 53 | export function onConfigSuccess(pCallbackObj) { 54 | /** 55 | * Set the UI to it's starting state 56 | */ 57 | document.querySelector('.card-input__spinner__holder').style.display = 'none'; 58 | 59 | // For <= v4.5.0 no rootNode prop was sent on the pCallbackObj 60 | const rootNode = pCallbackObj.rootNode || document.getElementById('card-container'); 61 | 62 | rootNode.style.display = 'block'; 63 | 64 | rootNode.querySelector('.pm-image-dual').style.display = 'none'; 65 | 66 | setLogosActive(rootNode); 67 | 68 | /** 69 | * Set focus on first element 70 | */ 71 | setTimeout(() => { 72 | // Allow time for screen to redraw after spinner is hidden 73 | window.securedFields.setFocusOn('encryptedCardNumber'); 74 | }, 100); 75 | 76 | // window.securedFields.updateStyles({ 77 | // base: { 78 | // color: '#000', 79 | //// fontSize: '18px', 80 | //// lineHeight: '18px' 81 | // }, 82 | // error: { 83 | // color: 'orange' 84 | // }, 85 | // validated: { 86 | // color: 'blue', 87 | // fontWeight: 'bold' 88 | // }, 89 | // placeholder: { 90 | // color: 'green' 91 | // } 92 | // }); 93 | } 94 | 95 | export function setCCErrors(pCallbackObj) { 96 | if (!pCallbackObj.rootNode) return; 97 | 98 | const sfNode = pCallbackObj.rootNode.querySelector(`[data-cse="${pCallbackObj.fieldType}"]`); 99 | const errorNode = sfNode.parentNode.querySelector('.pm-form-label__error-text'); 100 | 101 | if (errorNode.innerText === '' && pCallbackObj.error === '') return; 102 | 103 | if (pCallbackObj.error !== '') { 104 | errorNode.style.display = 'block'; 105 | errorNode.innerText = pCallbackObj.errorI18n; 106 | 107 | // Add error classes 108 | setErrorClasses(sfNode, true); 109 | return; 110 | } 111 | 112 | // Else: error === '' 113 | errorNode.style.display = 'none'; 114 | errorNode.innerText = ''; 115 | 116 | // Remove error classes 117 | setErrorClasses(sfNode, false); 118 | } 119 | 120 | export function setFocus(pCallbackObj) { 121 | const sfNode = pCallbackObj.rootNode.querySelector(`[data-cse="${pCallbackObj.fieldType}"]`); 122 | setFocusClasses(sfNode, pCallbackObj.focus); 123 | } 124 | 125 | export function onBrand(pCallbackObj) { 126 | /** 127 | * If not in dual branding mode - add card brand to first image element 128 | */ 129 | if (!isDualBranding) { 130 | const brandLogo1 = pCallbackObj.rootNode.querySelector('.pm-image-1'); 131 | setAttributes(brandLogo1, { 132 | src: pCallbackObj.brandImageUrl, 133 | alt: pCallbackObj.brand 134 | }); 135 | } 136 | 137 | /** 138 | * Deal with showing/hiding CVC field 139 | */ 140 | const cvcNode = pCallbackObj.rootNode.querySelector('.pm-form-label--cvc'); 141 | 142 | if (pCallbackObj.cvcPolicy === 'hidden' && !hideCVC) { 143 | hideCVC = true; 144 | cvcNode.style.display = 'none'; 145 | } 146 | 147 | if (hideCVC && pCallbackObj.cvcPolicy !== 'hidden') { 148 | hideCVC = false; 149 | cvcNode.style.display = 'block'; 150 | } 151 | 152 | // Optional cvc fields 153 | if (pCallbackObj.cvcPolicy === 'optional' && !optionalCVC) { 154 | optionalCVC = true; 155 | if (cvcNode) cvcNode.querySelector('.pm-form-label__text').innerText = 'CVV/CVC (optional):'; 156 | } 157 | 158 | if (optionalCVC && pCallbackObj.cvcPolicy !== 'optional') { 159 | optionalCVC = false; 160 | if (cvcNode) cvcNode.querySelector('.pm-form-label__text').innerText = 'CVV/CVC'; 161 | } 162 | 163 | /** 164 | * Deal with showing/hiding date field(s) 165 | */ 166 | const dateNode = pCallbackObj.rootNode.querySelector('.pm-form-label--exp-date'); 167 | const monthNode = pCallbackObj.rootNode.querySelector('.pm-form-label--exp-month'); 168 | const yearNode = pCallbackObj.rootNode.querySelector('.pm-form-label--exp-year'); 169 | 170 | if (pCallbackObj.expiryDatePolicy === 'hidden' && !hideDate) { 171 | hideDate = true; 172 | if (dateNode) dateNode.style.display = 'none'; 173 | if (monthNode) monthNode.style.display = 'none'; 174 | if (yearNode) yearNode.style.display = 'none'; 175 | } 176 | 177 | if (hideDate && pCallbackObj.expiryDatePolicy !== 'hidden') { 178 | hideDate = false; 179 | if (dateNode) dateNode.style.display = 'block'; 180 | if (monthNode) monthNode.style.display = 'block'; 181 | if (yearNode) yearNode.style.display = 'block'; 182 | } 183 | 184 | // Optional date fields 185 | if (pCallbackObj.expiryDatePolicy === 'optional' && !optionalDate) { 186 | optionalDate = true; 187 | if (dateNode) dateNode.querySelector('.pm-form-label__text').innerText = 'Expiry date (optional):'; 188 | if (monthNode) monthNode.querySelector('.pm-form-label__text').innerText = 'Expiry month (optional):'; 189 | if (yearNode) yearNode.querySelector('.pm-form-label__text').innerText = 'Expiry year (optional):'; 190 | } 191 | 192 | if (optionalDate && pCallbackObj.expiryDatePolicy !== 'optional') { 193 | optionalDate = false; 194 | if (dateNode) dateNode.querySelector('.pm-form-label__text').innerText = 'Expiry date:'; 195 | if (monthNode) monthNode.querySelector('.pm-form-label__text').innerText = 'Expiry month:'; 196 | if (yearNode) yearNode.querySelector('.pm-form-label__text').innerText = 'Expiry year:'; 197 | } 198 | } 199 | 200 | function dualBrandListener(e) { 201 | securedFields.dualBrandingChangeHandler(e); 202 | } 203 | 204 | function resetDualBranding(rootNode) { 205 | isDualBranding = false; 206 | 207 | setLogosActive(rootNode); 208 | 209 | const brandLogo1 = rootNode.querySelector('.pm-image-dual-1'); 210 | brandLogo1.removeEventListener('click', dualBrandListener); 211 | 212 | const brandLogo2 = rootNode.querySelector('.pm-image-dual-2'); 213 | brandLogo2.removeEventListener('click', dualBrandListener); 214 | } 215 | 216 | /** 217 | * Implementing dual branding 218 | */ 219 | function onDualBrand(pCallbackObj) { 220 | const brandLogo1 = pCallbackObj.rootNode.querySelector('.pm-image-dual-1'); 221 | const brandLogo2 = pCallbackObj.rootNode.querySelector('.pm-image-dual-2'); 222 | 223 | isDualBranding = true; 224 | 225 | const supportedBrands = pCallbackObj.supportedBrandsRaw; 226 | 227 | /** 228 | * Set first brand icon (and, importantly also add alt &/or data-value attrs); and add event listener 229 | */ 230 | setAttributes(brandLogo1, { 231 | src: supportedBrands[0].brandImageUrl, 232 | alt: supportedBrands[0].brand, 233 | 'data-value': supportedBrands[0].brand 234 | }); 235 | 236 | brandLogo1.addEventListener('click', dualBrandListener); 237 | 238 | /** 239 | * Set second brand icon (and, importantly also add alt &/or data-value attrs); and add event listener 240 | */ 241 | setAttributes(brandLogo2, { 242 | src: supportedBrands[1].brandImageUrl, 243 | alt: supportedBrands[1].brand, 244 | 'data-value': supportedBrands[1].brand 245 | }); 246 | brandLogo2.addEventListener('click', dualBrandListener); 247 | } 248 | 249 | export function onBinLookup(pCallbackObj) { 250 | /** 251 | * Dual branded result... 252 | */ 253 | if (pCallbackObj.supportedBrandsRaw?.length > 1) { 254 | onDualBrand(pCallbackObj); 255 | return; 256 | } 257 | 258 | /** 259 | * ...else - binLookup 'reset' result or binLookup result with only one brand 260 | */ 261 | resetDualBranding(pCallbackObj.rootNode); 262 | } 263 | 264 | export function onChangeV5(state, component) { 265 | // From v5 the onError handler is no longer only for card comp related errors 266 | // - so watch state.errors and use it to call the custom card specific 'setErrors' function 267 | if (!!Object.keys(state.errors).length) { 268 | const errors = Object.entries(state.errors).map(([fieldType, error]) => { 269 | return { 270 | fieldType, 271 | ...(error ? error : { error: '', rootNode: component._node }) 272 | }; 273 | }); 274 | errors.forEach(setCCErrors); 275 | } 276 | 277 | onChange(state); 278 | } 279 | 280 | export function onChange(state) { 281 | /** 282 | * If we're in a dual branding scenario & the number field becomes valid or is valid and become invalid 283 | * - set the brand logos to the required 'state' 284 | */ 285 | if (isDualBranding) { 286 | const mode = state.valid.encryptedCardNumber ? 'dualBranding_valid' : 'dualBranding_notValid'; 287 | setLogosActive(document.querySelector('#card-container'), mode); 288 | } 289 | } 290 | 291 | const setErrorClasses = function(pNode, pSetErrors) { 292 | if (pSetErrors) { 293 | if (pNode.className.indexOf('pm-input-field--error') === -1) { 294 | pNode.className += ' pm-input-field--error'; 295 | } 296 | return; 297 | } 298 | 299 | // Remove errors 300 | if (pNode.className.indexOf('pm-input-field--error') > -1) { 301 | const newClassName = pNode.className.replace('pm-input-field--error', ''); 302 | pNode.className = newClassName.trim(); 303 | } 304 | }; 305 | 306 | const setFocusClasses = function(pNode, pSetFocus) { 307 | if (pSetFocus) { 308 | if (pNode.className.indexOf('pm-input-field--focus') === -1) { 309 | pNode.className += ' pm-input-field--focus'; 310 | } 311 | return; 312 | } 313 | 314 | // Remove focus 315 | if (pNode.className.indexOf('pm-input-field--focus') > -1) { 316 | const newClassName = pNode.className.replace('pm-input-field--focus', ''); 317 | pNode.className = newClassName.trim(); 318 | } 319 | }; 320 | -------------------------------------------------------------------------------- /src/customcard/customcards.style.css: -------------------------------------------------------------------------------- 1 | #card-container{ 2 | position: relative; 3 | font-family: 'Open Sans', sans-serif; 4 | font-size: 14px; 5 | padding: 0 24px; 6 | display: none; 7 | } 8 | .pm-image, .pm-image-dual{ 9 | background-color: #ffffff; 10 | border-radius: 4px; 11 | -moz-border-radius: 4px; 12 | -webkit-border-radius: 4px; 13 | float: right; 14 | line-height: 0; 15 | position: relative; 16 | overflow: hidden; 17 | } 18 | .pm-form-label { 19 | float: left; 20 | padding-bottom: 1em; 21 | position: relative; 22 | width: 100%; 23 | } 24 | .pm-form-label--exp-date { 25 | width: 40%; 26 | } 27 | .pm-form-label--cvc { 28 | float: right; 29 | width: 40%; 30 | } 31 | .pm-form-label__text { 32 | color: #00112c; 33 | float: left; 34 | font-size: 0.93333em; 35 | padding-bottom: 6px; 36 | position: relative; 37 | } 38 | .pm-input-field { 39 | background: white; 40 | border: 1px solid #d8d8d8; 41 | -moz-border-radius: 4px; 42 | -webkit-border-radius: 4px; 43 | border-radius: 4px; 44 | box-sizing: border-box; 45 | clear: left; 46 | font-size: 0.93333333333em; 47 | float: left; 48 | padding: 8px; 49 | position: relative; 50 | width: 100%; 51 | height: 35px; 52 | } 53 | 54 | .pm-form-label__error-text { 55 | color: #ff7d00; 56 | display: none; 57 | float: left; 58 | font-size: 13px; 59 | padding-top: 0.4em; 60 | position: relative; 61 | width: 100%; 62 | } 63 | 64 | /* Set dynamically */ 65 | .pm-input-field--error{ 66 | border: 1px solid #ff7d00; 67 | } 68 | 69 | .pm-input-field--focus { 70 | border: 1px solid #969696; 71 | outline: none; 72 | } 73 | .pm-input-field--error.pm-input-field--focus { 74 | border: 1px solid #ff7d00; 75 | } 76 | 77 | .card-input__spinner__holder { 78 | position: relative; 79 | top: 0px; 80 | } 81 | 82 | .card-input__spinner { 83 | position: absolute; 84 | top: 0; 85 | left: 0; 86 | /*width: 100%;*/ 87 | height: 100%; 88 | z-index: 1; 89 | display: none; 90 | } 91 | 92 | .card-input__spinner--active { 93 | display: block; 94 | } 95 | -------------------------------------------------------------------------------- /src/customcard/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 | Back 17 | 18 |

Custom Card Component

19 |
20 |
21 | 22 | 28 | 29 | 30 | 35 | 40 | 41 | 46 | 51 | 56 | 61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 | 72 |
73 |

74 | Check the Source Code to see the full implementation. 75 |

76 |

77 | To make a payment, use our test card numbers. 79 |

80 |

81 | For more information, please refer to the Checkout 82 | Components documentation. 83 |

84 |
85 |
86 | 87 | 126 |
127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /src/demo.css: -------------------------------------------------------------------------------- 1 | *, 2 | *:after, 3 | *:before { 4 | box-sizing: border-box; 5 | } 6 | 7 | *::selection { 8 | background: #99c2ff; 9 | } 10 | 11 | *::-moz-selection { 12 | background: #99c2ff; 13 | } 14 | 15 | html, 16 | body { 17 | background: #fcfcfc; 18 | font: 16px/1.21 'Fakt', sans-serif, Helvetica, Arial; 19 | font-weight: 400; 20 | margin: 0; 21 | min-height: 100vh; 22 | overflow: auto; 23 | } 24 | 25 | h1, 26 | h2, 27 | h3 { 28 | font-weight: 400; 29 | } 30 | 31 | h1 { 32 | font-size: 2em; 33 | margin: 24px 0; 34 | line-height: 38px; 35 | } 36 | 37 | .sidebar .header { 38 | height: 60px; 39 | padding: 16px 24px; 40 | margin: 0; 41 | border-bottom: 1px solid rgba(255, 255, 255, 0.2); 42 | border-top: 1px solid rgba(255, 255, 255, 0.2); 43 | line-height: 1; 44 | } 45 | 46 | .sidebar h2 { 47 | display: inline-block; 48 | font-size: 1.25em; 49 | margin: 5px 0 0; 50 | } 51 | 52 | .sidebar .copy-sample-code { 53 | background: transparent; 54 | border: 1px solid white; 55 | border-radius: 3px; 56 | color: #fff; 57 | cursor: pointer; 58 | float: right; 59 | font-size: 0.65em; 60 | margin-top: -3px; 61 | text-transform: uppercase; 62 | padding: 8px 0; 63 | transition: 0.5s all; 64 | width: 60px; 65 | } 66 | 67 | .sidebar .copy-sample-code:hover { 68 | background: #183057; 69 | } 70 | 71 | .sidebar .copy-sample-code.copy-sample-code--active { 72 | border-color: #06f; 73 | background: #06f; 74 | transition: none; 75 | } 76 | 77 | .sidebar .copy-sample-code.copy-sample-code--active:before { 78 | content: 'Copied!'; 79 | } 80 | 81 | .sidebar .copy-sample-code:before { 82 | content: 'Copy'; 83 | } 84 | 85 | .pay-button { 86 | background: #001b2b; 87 | border: 0; 88 | border-radius: 3px; 89 | box-shadow: 0 3px 4px rgba(0, 15, 45, 0.2); 90 | color: #fff; 91 | cursor: pointer; 92 | font-size: 1em; 93 | font-weight: 700; 94 | height: 48px; 95 | margin-top: 20px; 96 | padding: 15px; 97 | transition: background 0.3s ease-out; 98 | width: 300px; 99 | } 100 | 101 | .pay-button[disabled] { 102 | cursor: not-allowed; 103 | opacity: 0.15; 104 | } 105 | 106 | .payment_methods__list { 107 | list-style: none; 108 | margin: 0; 109 | padding: 14px 0 14px; 110 | } 111 | 112 | @media (min-width: 780px) { 113 | .payment_methods__list { 114 | padding-left: 14px; 115 | } 116 | } 117 | 118 | .payment_methods__list__element { 119 | margin: 14px 0; 120 | } 121 | 122 | a:link, 123 | a:visited { 124 | color: #06f; 125 | text-decoration: none; 126 | } 127 | 128 | a:link:hover { 129 | text-decoration: underline; 130 | } 131 | 132 | .container { 133 | margin: 0 15px; 134 | max-width: 960px; 135 | height: 100vh; 136 | } 137 | 138 | @media (min-width: 400px) { 139 | .container { 140 | margin: auto; 141 | } 142 | } 143 | 144 | .container--full-width { 145 | margin: 0; 146 | max-width: 100vw; 147 | } 148 | 149 | @media (min-width: 400px) { 150 | .container--full-width { 151 | display: flex; 152 | } 153 | } 154 | 155 | .main { 156 | display: block; 157 | overflow-y: auto; 158 | padding: 18px 15px 48px; 159 | position: relative; 160 | } 161 | 162 | @media (min-width: 400px) { 163 | .main { 164 | padding: 18px 60px; 165 | width: 60%; 166 | } 167 | } 168 | 169 | .sidebar { 170 | background: #00112c; 171 | color: #fff; 172 | overflow: hidden; 173 | overflow-y: auto; 174 | } 175 | 176 | @media (min-width: 400px) { 177 | .sidebar { 178 | width: 40%; 179 | } 180 | } 181 | 182 | .info { 183 | background: #f3f6f9; 184 | border-left: 7px solid #06f; 185 | margin: 28px 0 0; 186 | padding: 7px 14px; 187 | } 188 | 189 | @media (min-width: 780px) { 190 | .info { 191 | padding: 7px 21px; 192 | } 193 | } 194 | 195 | pre { 196 | font-size: 0.95em; 197 | margin: 24px; 198 | overflow: auto; 199 | position: relative; 200 | } 201 | 202 | .request-container .request-code, 203 | .response-container .response-code { 204 | opacity: 0; 205 | transition: opacity 0.2s ease-out; 206 | } 207 | 208 | .request-container--visible .request-code, 209 | .response-container--visible .response-code { 210 | opacity: 1; 211 | } 212 | 213 | .request-container p, 214 | .response-container p { 215 | padding: 16px 24px; 216 | font-size: 0.9em; 217 | opacity: 0.7; 218 | } 219 | 220 | .request-container--visible p, 221 | .response-container--visible p { 222 | display: none; 223 | } 224 | 225 | .payment-method { 226 | border-radius: 3px; 227 | display: block; 228 | margin: 0 -15px; 229 | padding: 3em; 230 | background: #f7f8f9; 231 | display: flex; 232 | flex-direction: column; 233 | align-items: center; 234 | } 235 | 236 | @media (min-width: 780px) { 237 | .payment-method { 238 | margin: 0 auto; 239 | } 240 | } 241 | 242 | #bancontact-container, 243 | #wechatpay-container { 244 | min-width: 70%; 245 | max-width: 350px; 246 | } 247 | 248 | .payment-method__container { 249 | width: 350px; 250 | } 251 | 252 | #dropin-container { 253 | width: 544px; 254 | } 255 | 256 | #boletobancario-container, 257 | #boletobancario-result-container { 258 | width: 550px; 259 | } 260 | 261 | #result-container { 262 | background: #f7f8f9; 263 | padding: 0px 10px; 264 | } -------------------------------------------------------------------------------- /src/demo.js: -------------------------------------------------------------------------------- 1 | const stateContainer = document.querySelector('.current-state'); 2 | const requestContainer = document.querySelector('.request-container'); 3 | const responseContainer = document.querySelector('.response-container'); 4 | 5 | // Demo - Update current component state container 6 | function updateStateContainer(newState) { 7 | stateContainer.innerText = JSON.stringify(newState, null, 2); 8 | } 9 | 10 | // Demo - Update request container 11 | function updateRequestContainer(response) { 12 | const defaultResponseParams = { merchantAccount: 'YOUR_MERCHANT_ACCOUNT' }; 13 | requestContainer.querySelector('pre').innerText = JSON.stringify( 14 | { ...defaultResponseParams, ...response }, 15 | null, 16 | 2 17 | ); 18 | requestContainer.classList.add('request-container--visible'); 19 | } 20 | 21 | // Demo - Update server response container 22 | function updateResponseContainer(response) { 23 | responseContainer.querySelector('pre').innerText = JSON.stringify(response, null, 2); 24 | responseContainer.classList.add('response-container--visible'); 25 | } 26 | 27 | // Demo - Copy Source Code Examples 28 | document.querySelectorAll('.copy-sample-code').forEach(c => { 29 | c.addEventListener('click', () => { 30 | const code = document.querySelector('.source-code'); 31 | const range = document.createRange(); 32 | range.selectNode(code); 33 | window.getSelection().removeAllRanges(); 34 | window.getSelection().addRange(range); 35 | document.execCommand('copy'); 36 | c.classList.add('copy-sample-code--active'); 37 | 38 | setTimeout(() => { 39 | c.classList.remove('copy-sample-code--active'); 40 | }, 1000); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /src/dropin/dropin.js: -------------------------------------------------------------------------------- 1 | /** 2 | * IMPORTANT - Set a boolean indicating whether index.html is loading a version of adyen.js (& adyen.css) >= 5.0.0 3 | */ 4 | const head = document.head.innerHTML; 5 | const version = head.substring(head.indexOf('sdk/') + 4, head.indexOf('/adyen')); 6 | const majorVn = Number(version.substring(0, version.indexOf('.'))); 7 | const IS_VERSION_5 = majorVn >= 5; 8 | 9 | const DEFAULT_COUNTRY = 'US'; 10 | 11 | // 0. Get clientKey 12 | getClientKey().then(clientKey => { 13 | const urlParams = getSearchParameters(window.location.search); 14 | 15 | // Can add request params to this object 16 | const pmReqConfig = {countryCode: urlParams.countryCode || DEFAULT_COUNTRY}; 17 | getPaymentMethods(pmReqConfig).then(async paymentMethodsResponse => { 18 | 19 | paymentMethodsResponse.paymentMethods.reverse(); 20 | 21 | let allowedPMS = urlParams.allowedpms;// e.g. &allowedpms=[scheme,ideal] 22 | if(allowedPMS === '[]' || typeof allowedPMS === 'undefined') allowedPMS = [];// if empty, all PMs will show 23 | 24 | const configObj = { 25 | environment: 'test', 26 | clientKey: clientKey, // Mandatory. clientKey from Customer Area 27 | paymentMethodsResponse, 28 | // removePaymentMethods: ['paysafecard', 'c_cash'], 29 | allowPaymentMethods: allowedPMS, 30 | onChange: state => { 31 | updateStateContainer(state); // Demo purposes only 32 | }, 33 | onSubmit: (state, dropin) => { 34 | // state.data; 35 | // state.isValid; 36 | makePayment(state.data); 37 | } 38 | }; 39 | 40 | // 1. Create an instance of AdyenCheckout 41 | if (!IS_VERSION_5) { 42 | window.checkout = new AdyenCheckout(configObj); 43 | } else { 44 | window.checkout = await AdyenCheckout(configObj); 45 | } 46 | 47 | // 2. Create and mount the Component 48 | window.dropin = checkout 49 | .create('dropin', { 50 | // Events 51 | onSelect: activeComponent => { 52 | if (activeComponent.state && activeComponent.state.data) updateStateContainer(activeComponent.data); // Demo purposes only 53 | }, 54 | showStoredPaymentMethods: false 55 | }) 56 | .mount('#dropin-container'); 57 | 58 | }); 59 | }); 60 | -------------------------------------------------------------------------------- /src/dropin/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Adyen Checkout Components sample code 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |
17 | Back 18 | 19 |

Drop-in

20 |
21 |
22 | 23 |
24 |
25 |
26 | 27 |
28 |

29 | Check the Source Code to see the full implementation. 30 |

31 |

32 | To make a payment, use our test card numbers. 35 |

36 |

37 | For more information, please refer to the Drop-in documentation. 39 |

40 |
41 |
42 | 43 | 84 |
85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Adyen/adyen-components-js-sample-code/dd5a2925f714f636ebf80d2ea6224a62ce22b286/src/favicon.ico -------------------------------------------------------------------------------- /src/googlepay/googlepay.js: -------------------------------------------------------------------------------- 1 | async function initiateComponent() { 2 | // 1. Create an instance of AdyenCheckout 3 | const checkout = await AdyenCheckout({}); 4 | 5 | // 2. Create and mount the Component 6 | const googlepay = checkout 7 | .create('paywithgoogle', { 8 | showPayButton: true, 9 | environment: 'TEST', // Google Pay environment 10 | configuration: { 11 | gatewayMerchantId: 'TestMerchantCheckout', // name of your Adyen Merchant account 12 | merchantName: 'Adyen Test' // Name to be shown 13 | // merchantIdentifier: '' // Required in Production environment. Google's merchantId: https://developers.google.com/pay/api/web/guides/test-and-deploy/deploy-production-environment#obtain-your-merchantID 14 | }, 15 | 16 | // Events 17 | onSubmit: (state, component) => { 18 | // Submit Payment 19 | makePayment(state.data); 20 | 21 | updateStateContainer(state); // Demo purposes only 22 | }, 23 | onError: error => { 24 | console.error(error); 25 | } 26 | }) 27 | // Normally, you should check if Google Pay is available before mounting it. 28 | // Here we are mounting it directly for demo purposes. 29 | // Please refer to the documentation for more information on Google Pay's availability. 30 | .mount('#googlepay-container'); 31 | } 32 | initiateComponent() -------------------------------------------------------------------------------- /src/googlepay/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 |
13 |
14 | Back 15 | 16 |
17 |

Google Pay Component

18 |
19 | 20 |
21 | 22 |
23 |
24 |
25 | 26 |
27 |

28 | Check the Source Code to see the full implementation. 29 |

30 |

31 | For more information, please refer to the Checkout Components documentation. 32 |

33 |
34 |
35 | 36 | 86 |
87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /src/ideal/ideal.js: -------------------------------------------------------------------------------- 1 | getPaymentMethods().then(async response => { 2 | // 1. Create an instance of AdyenCheckout 3 | const checkout = await AdyenCheckout({ 4 | paymentMethodsResponse: response, 5 | 6 | // Optionally show a Pay Button 7 | showPayButton: true, 8 | 9 | // Events 10 | onSubmit: (state, component) => { 11 | // Triggered when a shopper clicks on the Pay button 12 | makePayment(state.data); 13 | }, 14 | onChange: (state, component) => { 15 | updateStateContainer(state); // Demo purposes only 16 | } 17 | }); 18 | 19 | // 2. Create and mount the Component 20 | const ideal = checkout.create('ideal').mount('#ideal-container'); 21 | }); -------------------------------------------------------------------------------- /src/ideal/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | Back 16 | 17 |

iDEAL Component

18 |
19 |
20 | 21 |
22 |
23 |
24 |
25 |

26 | Check the Source Code to see the full implementation. 27 |

28 |

29 | For more information, please refer to the Checkout Components documentation. 30 |

31 |
32 |
33 | 34 | 69 |
70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 |
12 |

Adyen Checkout Components sample code

13 | 14 |

15 | Components are our drop-in JavaScript modules that you can add to your payment page. 16 |
17 | They render as input fields that collect required shopper details, and provide the values you need to make a payment. 18 |

19 | 20 | 21 | 65 | 66 |
67 |

68 | For more information, please refer to the Checkout Components documentation. 69 |

70 |
71 |
72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/multibanco/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | Back 16 | 17 |

Multibanco Component

18 |
19 | 20 |
21 | 22 |
23 |
24 |
25 |
26 |

27 | Check the Source Code to see the full implementation. 28 |

29 |

30 | For more information, please refer to the Checkout Components documentation. 31 |

32 |
33 |
34 | 35 | 64 |
65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/multibanco/multibanco.js: -------------------------------------------------------------------------------- 1 | // 0. Get clientKey 2 | getClientKey().then(clientKey => { 3 | getPaymentMethods().then(async paymentMethodsResponse => { 4 | // 1. Create an instance of AdyenCheckout 5 | const checkout = await AdyenCheckout({ 6 | clientKey: clientKey, // Mandatory. clientKey from Customer Area 7 | environment: 'test', 8 | amount: { 9 | currency: 'EUR', 10 | value: 1000 11 | }, 12 | onAdditionalDetails: result => { 13 | console.log(result); 14 | }, 15 | onError: error => { 16 | console.log(error); 17 | }, 18 | onSubmit: initialSubmit, 19 | paymentMethodsResponse 20 | }); 21 | 22 | function initialSubmit(state, component) { 23 | makePayment(state.data).then(response => { 24 | component.unmount(); 25 | // 3. present the voucher using the action object returned from /payments 26 | checkout.createFromAction(response.action).mount('#multibanco-container'); 27 | }); 28 | } 29 | 30 | // 2. create Multibanco component 31 | checkout.create('multibanco').mount('#multibanco-container'); 32 | 33 | }); 34 | }); -------------------------------------------------------------------------------- /src/sepa/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 |
13 |
14 | Back 15 | 16 |
17 |

SEPA Direct Debit Component

18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 |
26 |

27 | Check the Source Code to see the full implementation. 28 |

29 |

30 | To make a payment, use our SEPA Direct Debit test credentials. 31 |

32 |

33 | For more information, please refer to the Checkout Components documentation. 34 |

35 |
36 |
37 | 38 | 75 |
76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /src/sepa/sepa.js: -------------------------------------------------------------------------------- 1 | async function initiateComponent() { 2 | // 1. Create an instance of AdyenCheckout 3 | const checkout = await AdyenCheckout({ 4 | environment: 'test', 5 | onChange: (state, component) => { 6 | // state.data; 7 | // state.isValid; 8 | 9 | updateStateContainer(state); // Demo purposes only 10 | } 11 | }); 12 | 13 | // 2. Create and mount the Component 14 | const sepa = checkout 15 | .create('sepadirectdebit', { 16 | showPayButton: true, 17 | countryCode: 'NL', // Optional. Sets the default country of the IBAN Placeholder 18 | placeholders: { 19 | // Optional. Overwriting the default placeholders 20 | // ownerName: '', 21 | // ibanNumber: '' 22 | }, 23 | 24 | // Events 25 | onSubmit: (state, component) => { 26 | makePayment(state.data); 27 | } 28 | }) 29 | .mount('#sepa-container'); 30 | } 31 | initiateComponent() -------------------------------------------------------------------------------- /src/sessions/dropin.js: -------------------------------------------------------------------------------- 1 | getClientKey().then(clientKey => { 2 | 3 | // Check URL for redirectResult and sessionId 4 | const queryResultString = window.location.search; 5 | const urlParams = new URLSearchParams(queryResultString) 6 | const redirectResult = urlParams.get('redirectResult') 7 | const sessionId = urlParams.get('sessionId') 8 | 9 | function initiateSession() { 10 | sessions() 11 | .then(response => { 12 | const configuration = { 13 | environment: 'test', // Change to 'live' for the live environment. 14 | clientKey: clientKey, // Public key used for client-side authentication: https://docs.adyen.com/development-resources/client-side-authentication 15 | session: { 16 | id: response.id, // Unique identifier for the payment session. 17 | sessionData: response.sessionData // The payment session data. 18 | }, 19 | onPaymentCompleted: (result, component) => { 20 | console.info(result, component); 21 | updateResponseContainer(result); 22 | }, 23 | onError: (error, component) => { 24 | console.error(error.name, error.message, error.stack, component); 25 | }, 26 | onChange: (state, component) => { 27 | updateStateContainer(state); // Demo purposes only 28 | }, 29 | beforeSubmit: (data, component, actions) => { 30 | updateRequestContainer(data); 31 | actions.resolve(data); 32 | }, 33 | // Any payment method specific configuration. Find the configuration specific to each payment method: https://docs.adyen.com/payment-methods 34 | // For example, this is 3D Secure configuration for cards: 35 | paymentMethodsConfiguration: { 36 | card: { 37 | // Optional configuration 38 | hasHolderName: true, 39 | holderNameRequired: true 40 | } 41 | } 42 | }; 43 | async function initiateCheckout() { 44 | // Create an instance of AdyenCheckout using the configuration object. 45 | const checkout = await AdyenCheckout(configuration); 46 | 47 | // Create an instance of Drop-in and mount it to the container you created. 48 | const dropinComponent = checkout.create('dropin', { 49 | onSelect: activeComponent => { 50 | if (activeComponent.state && activeComponent.state.data) updateStateContainer(activeComponent.data); // Demo purposes only 51 | } 52 | }).mount('#dropin-container'); 53 | } 54 | initiateCheckout() 55 | }) 56 | } 57 | 58 | async function handleRedirect() { 59 | const configuration = { 60 | environment: 'test', // Change to 'live' for the live environment. 61 | clientKey: clientKey, // Public key used for client-side authentication: https://docs.adyen.com/development-resources/client-side-authentication 62 | session: { 63 | id: sessionId, // Retreived identifier for the payment completion on redirect. 64 | }, 65 | onPaymentCompleted: (result, component) => { 66 | console.info(result) 67 | const paymentResult = result.resultCode 68 | if (paymentResult === 'Authorised' || paymentResult === 'Received') { 69 | document.getElementById('result-container').innerHTML = 'Success'; 70 | 71 | } else { 72 | document.getElementById('result-container').innerHTML = 'Error' 73 | } 74 | updateResponseContainer(result); 75 | }, 76 | onError: (error, component) => { 77 | console.error(error.name, error.message, error.stack, component); 78 | }, 79 | }; 80 | // Create an instance of AdyenCheckout to handle the shopper returning to your website. 81 | // Configure the instance with the sessionId you extracted from the returnUrl. 82 | const checkout = await AdyenCheckout(configuration); 83 | // Submit the redirectResult value you extracted from the returnUrl. 84 | checkout.submitDetails({ details: { redirectResult } }); 85 | } 86 | 87 | // If no paramters are present in the URL, mount the Drop-in 88 | if (!redirectResult && !sessionId) { 89 | initiateSession() 90 | // Otherwise, handle the redirect 91 | } else { 92 | handleRedirect() 93 | } 94 | }) -------------------------------------------------------------------------------- /src/sessions/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | Back 16 | 17 |

Sessions Drop-in

18 |
19 |
20 | 21 |
22 |
23 |
24 |
25 | 26 |
27 |

28 | Check the Source Code to see the full implementation. 29 |

30 |

31 | To make a payment, use our test card numbers. 32 |

33 |

34 | For more information, please refer to the Drop-in documentation. 35 |

36 |
37 |
38 | 39 | 84 |
85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /src/swish/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 |
13 |
14 |
15 | Back 16 | 17 |

Swish Component

18 |
19 |
20 | 21 |
22 |
23 |
24 |
25 |

26 | Check the Source Code to see the full implementation. 27 |

28 |

29 | For more information, please refer to the Checkout Components documentation. 30 |

31 |
32 |
33 | 34 | 69 |
70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/swish/swish.js: -------------------------------------------------------------------------------- 1 | // 0. Get clientKey 2 | getClientKey().then(async clientKey => { 3 | // 1. Create an instance of AdyenCheckout 4 | const checkout = await AdyenCheckout({ 5 | clientKey: clientKey, // Mandatory. clientKey from Customer Area 6 | environment: 'test', 7 | amount: { 8 | currency: 'EUR', 9 | value: 1000 10 | }, 11 | onAdditionalDetails: result => { 12 | console.log(result); 13 | }, 14 | onError: error => { 15 | console.log(error); 16 | } 17 | }); 18 | 19 | const swishData = { 20 | paymentMethod: { 21 | type: 'swish' 22 | }, 23 | countryCode: 'SE', 24 | amount: { 25 | currency: 'SEK', 26 | value: 10000 27 | } 28 | }; 29 | 30 | makePayment(swishData).then(response => { 31 | checkout.createFromAction(response.action).mount('#swish-container'); 32 | }); 33 | }); -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | // Function to set returnUrl, for standard Drop-in and Components, return to placeholder, 2 | // else redirect back to sessions where we handle the redirectResult 3 | function setReturnUrl() { 4 | if (window.location.pathname === '/sessions/') { 5 | return window.location.href 6 | } else { 7 | return window.location.href;//'https://your-company.com/' 8 | } 9 | } 10 | 11 | const paymentMethodsConfig = { 12 | shopperReference: 'Checkout Components sample code test', 13 | reference: 'Checkout Components sample code test', 14 | countryCode: 'NL', 15 | amount: { 16 | value: 1000, 17 | currency: 'EUR' 18 | } 19 | }; 20 | 21 | const paymentsDefaultConfig = { 22 | shopperReference: 'Checkout Components sample code test', 23 | reference: 'Checkout Components sample code test', 24 | countryCode: 'NL', 25 | channel: 'Web', 26 | returnUrl: setReturnUrl(), 27 | amount: { 28 | value: 1000, 29 | currency: 'EUR' 30 | }, 31 | lineItems: [ 32 | { 33 | id: '1', 34 | description: 'Test Item 1', 35 | amountExcludingTax: 10000, 36 | amountIncludingTax: 11800, 37 | taxAmount: 1800, 38 | taxPercentage: 1800, 39 | quantity: 1, 40 | taxCategory: 'High' 41 | } 42 | ] 43 | }; 44 | 45 | // Generic POST Helper 46 | const httpPost = (endpoint, data) => 47 | fetch(`/${endpoint}`, { 48 | method: 'POST', 49 | headers: { 50 | Accept: 'application/json, text/plain, */*', 51 | 'Content-Type': 'application/json' 52 | }, 53 | body: JSON.stringify(data) 54 | }).then(response => response.json()); 55 | 56 | // Get all available payment methods from the local server 57 | const getPaymentMethods = (config = {}) => 58 | httpPost('paymentMethods', { ...paymentMethodsConfig, ...config }) 59 | .then(response => { 60 | if (response.error) throw 'No paymentMethods available'; 61 | 62 | return response; 63 | }) 64 | .catch(console.error); 65 | 66 | // Posts a new payment into the local server 67 | const makePayment = (paymentMethod, config = {}) => { 68 | const paymentsConfig = { ...paymentsDefaultConfig, ...config }; 69 | const paymentRequest = { ...paymentsConfig, ...paymentMethod }; 70 | 71 | updateRequestContainer(paymentRequest); 72 | 73 | return httpPost('payments', paymentRequest) 74 | .then(response => { 75 | if (response.error) throw 'Payment initiation failed'; 76 | 77 | alert(response.resultCode); 78 | updateResponseContainer(response); 79 | 80 | return response; 81 | }) 82 | .catch(console.error); 83 | }; 84 | 85 | const handleAdditionalDetails = (details, component) => { 86 | 87 | updateRequestContainer(details.data); 88 | 89 | return httpPost('details', details.data) 90 | .then(response => { 91 | if (response.error) throw 'Details call failed'; 92 | 93 | alert(response.resultCode); 94 | updateResponseContainer(response); 95 | 96 | return response; 97 | }) 98 | .catch(console.error); 99 | }; 100 | 101 | // Posts a new payment into the local server 102 | const sessions = (paymentMethod, config = {}) => { 103 | const paymentsConfig = { ...paymentsDefaultConfig, ...config }; 104 | const sessionRequest = { ...paymentsConfig, ...paymentMethod }; 105 | 106 | return httpPost('sessions', sessionRequest) 107 | .then(response => { 108 | if (response.error) throw 'Payment initiation failed'; 109 | return response; 110 | }) 111 | .catch(console.error); 112 | }; 113 | 114 | 115 | // Fetches an originKey from the local server 116 | const getOriginKey = () => 117 | httpPost('originKeys') 118 | .then(response => { 119 | if (response.error || !response.originKeys) throw 'No originKey available'; 120 | 121 | return response.originKeys[Object.keys(response.originKeys)[0]]; 122 | }) 123 | .catch(console.error); 124 | 125 | // Fetches a clientKey from the 126 | const getClientKey = () => 127 | httpPost('clientKeys') 128 | .then(response => { 129 | if (response.error || !response.clientKey) throw 'No clientKey available'; 130 | 131 | return response.clientKey; 132 | }) 133 | .catch(console.error); 134 | 135 | const getSearchParameters = (search = window.location.search) => 136 | search 137 | .replace(/\?/g, '') 138 | .split('&') 139 | .reduce((acc, cur) => { 140 | const [key, prop = ''] = cur.split('='); 141 | acc[key] = decodeURIComponent(prop); 142 | return acc; 143 | }, {}); -------------------------------------------------------------------------------- /src/wechatpay/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Adyen Checkout Components sample code 8 | 9 | 10 | 11 | 12 |
13 |
14 | Back 15 | 16 |
17 |

WeChat Pay Component

18 |
19 |
20 | 21 |
22 |
23 |
24 | 25 |
26 |

Check the Source Code to see the full implementation.

27 |

For more information, please refer to the Checkout Components documentation.

28 |
29 |
30 | 31 | 61 |
62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /src/wechatpay/wechatpay.js: -------------------------------------------------------------------------------- 1 | // 0. Get clientKey 2 | getClientKey().then(async clientKey => { 3 | // 1. Create an instance of AdyenCheckout providing the clientKey 4 | const checkout = await AdyenCheckout({ 5 | environment: 'test', 6 | clientKey: clientKey, // Mandatory. clientKey from Customer Area 7 | amount: { 8 | currency: 'CNY', 9 | value: 1000 10 | }, // amount to be shown next to the qrcode 11 | onAdditionalDetails: state => { 12 | console.log(state.data); 13 | }, 14 | onError: error => { 15 | console.log(error); 16 | } 17 | }); 18 | 19 | // Override our default demo config for this payment method 20 | const wechatData = { 21 | countryCode: 'CN', 22 | amount: { 23 | value: 1000, 24 | currency: 'CNY' 25 | }, 26 | paymentMethod: { 27 | type: 'wechatpayQR' 28 | } 29 | }; 30 | 31 | /** Call the /payments endpoint to retrieve the necessary data to start the Wechat Pay component 32 | * We need the following parts of the response 33 | * - qrCodeData (redirect.data.qrCodeData): The data the QR Code will contain 34 | * - paymentData Necessary to communicate with Adyen to check the current payment status 35 | */ 36 | makePayment(wechatData).then(response => { 37 | if (!!response.action) { 38 | // 2. Create and mount the Component from the action received 39 | const wechatpay = checkout.createFromAction(response.action).mount('#wechatpay-container'); 40 | } 41 | }); 42 | }); -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | ./server/php/start.sh 2 | --------------------------------------------------------------------------------