Applies to: Web Payments SDK | Customers API
Learn how to add code to your application to charge a card on file with Strong Customer Authentication (SCA).
You can add code to the application you created (with a card payment) from the quickstart project sample, as documented in Web Payments SDK Quickstart. If you haven't created an application using the quickstart, you need to do so before completing the following steps.
You can see a complete code example in the Web Payments Quickstart on GitHub.
The form inputs take the customer ID and card ID associated with a customer.
<body>
<form id="payment-form">
<input
id="customer-input"
type="text"
aria-required="true"
aria-label="Customer ID"
required="required"
placeholder="Customer ID"
name="customerId"
/>
<input
id="card-input"
type="text"
aria-required="true"
aria-label="Card ID"
required="required"
placeholder="Card ID"
name="cardId"
/>
<button id="card-button" type="button">Pay $1.00</button>
</form>
<div id="payment-status-container"></div>
</body>
Note
All subsequent steps make revisions to the code inside the <script>
tag.
Update the cardButton.addEventListener
callback method with the following code.
The event listener validates the text from the input form field and stores the IDs in variables. The handlePaymentWithCardOnFileMethodSubmission
method is called with the customer ID and card ID.
const cardButton = document.getElementById('card-button');
cardButton.addEventListener('click', async function (event) {
const customerTextInput = document.getElementById('customer-input');
const cardTextInput = document.getElementById('card-input');
if (
!customerTextInput.reportValidity() ||
!cardTextInput.reportValidity()
) {
return;
}
const cardId = cardTextInput.value;
const customerId = customerTextInput.value;
handlePaymentWithCardOnFileMethodSubmission(
event,
cardId,
customerId
);
});
Add the following code after the appId
and locationId
global constants:
async function createPaymentWithCardOnFile(sourceId, customerId) {
const bodyParameters = {
locationId,
sourceId,
customerId,
};
const body = JSON.stringify(bodyParameters);
const paymentResponse = await fetch('/payment', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body,
});
if (paymentResponse.ok) {
return paymentResponse.json();
}
const errorBody = await paymentResponse.text();
throw new Error(errorBody);
}
Replace the handlePaymentMethodSubmission
function call with handlePaymentWithCardOnFileMethodSubmission
using customer ID and card ID arguments.
The handlePaymentWithCardOnFileMethodSubmission
method receives information about the card on file payment event with the customer ID.
async function handlePaymentWithCardOnFileMethodSubmission(event, cardId, customerId) {
event.preventDefault();
try {
// disable the submit button as we await tokenization and make a payment request.
cardButton.disabled = true;
const paymentResults = await createPaymentWithCardOnFile(
cardId,
customerId
);
displayPaymentResults('SUCCESS');
console.debug('Payment Success', paymentResults);
} catch (e) {
cardButton.disabled = false;
displayPaymentResults('FAILURE');
console.error(e.message);
}
}
Navigate to http://localhost:3000/ in your browser. The browser loads the form with the customer ID input field, card ID field, and the Pay $1.00 button.
In another browser tab, log in to your Square developer account and access API Explorer in your Sandbox environment.
Get the customer ID from a customer profile. If you don't have a customer profile for testing, use the CreateCustomer endpoint of the Customers API to create a new test customer profile in API Explorer.
On the form, enter the customer ID, enter the
ccof:customer-card-id-ok
test card ID, and choose Pay $1.00.Did you know?
The
cardId
generated from using a Sandbox credit card works in the Square Sandbox environment.Verify that the application made a successful payment request. In the Developer Console, open the application that you're testing and choose API Logs in the left pane.
Important
Your application should always attempt to create a payment with a verification token when a token is returned. It should also be prepared to respond to a payment failure in a small number of cases where a payment is rejected despite receiving a buyer verification token.
Update the
createPaymentWithCardOnFile
method to include theverificationToken
parameter.async function createPaymentWithCardOnFile( sourceId, customerId, verificationToken ) { const bodyParameters = { locationId, sourceId, customerId, verificationToken, }; const body = JSON.stringify(bodyParameters); const paymentResponse = await fetch('/payment', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body, }); if (paymentResponse.ok) { return paymentResponse.json(); } const errorBody = await paymentResponse.text(); throw new Error(errorBody); }Define the
verifyBuyer
function.Your production application should collect the billing address of the buyer. Although providing an empty
billingContact
is acceptable, by providing as much billing contact information as possible, you increase the chances of a successful authentication. This example uses an object that's declared with a hard-coded billing address. Your application might collect a billing address at payment time or, if the buyer is a customer on the seller Square account, from the buyer's customer record.Note
The Web Payments SDK produces a payment token that can be used to make a payment with the presented card or to store the card on file. These operations are represented by two intents:
CHARGE
to make a payment andSTORE
to store the card.The code in the following steps adds the billing contact values needed by SCA (with the payments.verifyBuyer function) to verify the authenticity of the card holder:
async function verifyBuyer(payments, sourceId) { const verificationDetails = { amount: '1.00', billingContact: { addressLines: ['123 Main Street', 'Apartment 1'], familyName: 'Doe', givenName: 'John', email: '[email protected]', country: 'GB', phone: '3214563987', region: 'LND', city: 'London', }, currencyCode: 'GBP', intent: 'CHARGE', }; const verificationResults = await payments.verifyBuyer( sourceId, verificationDetails ); return verificationResults.token; }The parameter argument that you pass to
verifyBuyer
is for card verification. After you pass in the argument, theverifyBuyer
function creates a ChargeVerifyBuyerDetails object that verifies the buyer's card on file to be charged and provides 3DS with information about the buyer and the purchase details.Call the
verifyBuyer
function in the submission method.async function handlePaymentWithCardOnFileMethodSubmission( event, cardId, customerId ) { event.preventDefault(); try { // disable the submit button as we await tokenization and make a payment request. cardButton.disabled = true; let verificationToken = await verifyBuyer(payments, cardId); const paymentResults = await createPaymentWithCardOnFile( cardId, customerId, verificationToken ); displayPaymentResults('SUCCESS'); console.debug('Payment Success', paymentResults); } catch (e) { cardButton.disabled = false; displayPaymentResults('FAILURE'); console.error(e.message); } }Test the application.
Navigate to http://localhost:3000/ in your browser.
Enter the card ID
ccof:customer-card-id-requires-verification
on the form. When the modal window prompt displays, enter 123456.Did you know?
The
cardId
generated from using a Sandbox SCA credit card works in the Square Sandbox environment.Verify that the application passed in the verification token with a successful response. Check the application API log again in your developer account.