Site name: lucid-brattain-8cb631
The content in question is available on a branch called sqpaymentform
.
I am trying to implement Square’s Payment Form on a website that I have built and deployed using Jekyll and Netlify. I have successfully followed Square’s walkthrough to build the payment form locally using node.js.
When I add the server.js script as a Netlify function, the site will build successfully but when I try to use the payment form to hit the server.js function, I get a 404 error. The only changes I have made to the files provided by Square are updating the path to the function to match Netlify’s function endpoints (line 85 in the payment form and line 36 in server.js). I have also added serverless-http
per the Netlify instructions for hosting express.js apps in Netlify Functions.
server.js
const express = require('express');
const serverless = require('serverless-http');
const bodyParser = require('body-parser');
const { Client, Environment, ApiError } = require('square');
const app = express();
const port = 3000;
// Set the Access Token which is used to authorize to a merchant
const accessToken = 'REMOVED_ACCESS_TOKEN';
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(__dirname));
// Initialized the Square api client:
// Set sandbox environment for testing purpose
// Set access token
const client = new Client({
environment: Environment.Sandbox,
accessToken: accessToken,
});
app.post('.netlify/functions/process-payment', async (req, res) => {
const requestParams = req.body;
// Charge the customer's card
const paymentsApi = client.paymentsApi;
const requestBody = {
sourceId: requestParams.nonce,
amountMoney: {
amount: 100, // $1.00 charge
currency: 'USD'
},
locationId: requestParams.location_id,
idempotencyKey: requestParams.idempotency_key,
};
try {
const response = await paymentsApi.createPayment(requestBody);
res.status(200).json({
'title': 'Payment Successful',
'result': response.result
});
} catch(error) {
let errorResult = null;
if (error instanceof ApiError) {
errorResult = error.errors;
} else {
errorResult = error;
}
res.status(500).json({
'title': 'Payment Failure',
'result': errorResult
});
}
});
app.listen(
port,
() => console.log(`listening on - http://localhost:${port}`)
);
module.exports.handler = serverless(app);
payment-form.html
<div id="form-container">
<div id="sq-card-number"></div>
<div class="third" id="sq-expiration-date"></div>
<div class="third" id="sq-cvv"></div>
<div class="third" id="sq-postal-code"></div>
<button id="sq-creditcard" class="button-credit-card" onclick="onGetCardNonce(event)">Pay $1.00</button>
</div> <!-- end #form-container -->
<script type="text/javascript">
//TODO: paste code from step 2.1.1
const idempotency_key = uuidv4();
// Create and initialize a payment form object
const paymentForm = new SqPaymentForm({
// Initialize the payment form elements
//TODO: Replace with your sandbox application ID
applicationId: "sandbox-sq0idb-MYmeor4LAw5C0tBRgJ0uBQ",
inputClass: 'sq-input',
autoBuild: false,
// Customize the CSS for SqPaymentForm iframe elements
inputStyles: [{
fontSize: '16px',
lineHeight: '24px',
padding: '16px',
placeholderColor: '#a0a0a0',
backgroundColor: 'transparent',
}],
// Initialize the credit card placeholders
cardNumber: {
elementId: 'sq-card-number',
placeholder: 'Card Number'
},
cvv: {
elementId: 'sq-cvv',
placeholder: 'CVV'
},
expirationDate: {
elementId: 'sq-expiration-date',
placeholder: 'MM/YY'
},
postalCode: {
elementId: 'sq-postal-code',
placeholder: 'Postal'
},
// SqPaymentForm callback functions
callbacks: {
/*
* callback function: cardNonceResponseReceived
* Triggered when: SqPaymentForm completes a card nonce request
*/
cardNonceResponseReceived: function (errors, nonce, cardData) {
if (errors) {
// Log errors from nonce generation to the browser developer console.
console.error('Encountered errors:');
errors.forEach(function (error) {
console.error(' ' + error.message);
});
alert('Encountered errors, check browser developer console for more details');
return;
}
//TODO: Replace alert with code in step 2.1
fetch('/.netlify/functions/process-payment', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({
nonce: nonce,
idempotency_key: idempotency_key,
location_id: "LVEKPR22VWSXS"
})
})
.catch(err => {
alert('Network error: ' + err);
})
.then(response => {
if (!response.ok) {
return response.json().then(
errorInfo => Promise.reject(errorInfo));
}
return response.json();
})
.then(data => {
console.log(data);
alert('Payment complete successfully!\nCheck browser developer console for more details');
})
.catch(err => {
console.error(err);
alert('Payment failed to complete!\nCheck browser developer console for more details');
});
}
}
});
//TODO: paste code from step 1.1.4
//TODO: paste code from step 1.1.5
paymentForm.build();
//TODO: paste code from step 2.1.2
//Generate a random UUID as an idempotency key for the payment request
// length of idempotency_key should be less than 45
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
// onGetCardNonce is triggered when the "Pay $1.00" button is clicked
function onGetCardNonce(event) {
// Don't submit the form until SqPaymentForm returns with a nonce
event.preventDefault();
// Request a nonce from the SqPaymentForm object
paymentForm.requestCardNonce();
}
</script>
Can anyone help me figure out why I am getting a 404 error and how to update the script / payment form so that I can access this function via Netlify? Thanks!
Edit: the included API keys are all sandbox keys, by the way.