Introduction
Integrating payment processing systems into Salesforce allows businesses to securely handle transactions while leveraging Salesforce’s CRM capabilities. By using Lightning Web Components (LWC) and Apex, developers can create responsive interfaces for seamless payment experiences with gateways like Stripe or PayPal. This integration enhances operational efficiency, automates invoicing, and provides real-time transaction tracking, improving both financial accuracy and customer satisfaction.
Steps To Create an Account On Stripe And Get Credentials
- Visit the Stripe Website:
- Go to stripe.com.
- Sign Up for an Account:
- Click on Start Now or Sign up.
- Enter your email address, and full name, and create a password.
- Click on Create account.
- Verify Your Email:
- Check your email inbox for a verification email from Stripe.
- Click the link in the email to verify your account.
- Access the Dashboard:
- Log in to your Stripe dashboard after verifying your email.
- Enable Test Mode:
- In the dashboard, navigate to the Developers section.
- Ensure you are in Test Mode (you can toggle between Test and Live mode using the switch at the top of the dashboard).
- Obtain API Keys:
- Under the Developers section, click on API keys.
- You will find two sets of keys
- Publishable Key
- Secret Key
- Copy these keys for use in your application.
- Use Test Card Numbers:
- You can use Stripe’s test card numbers to simulate transactions without real money. For example, use 4242 4242 4242 4242 with any future expiration date and any CVC.
Steps To Access Card Details
- Log in to Your Stripe Dashboard:
- Visit stripe.com and log in to your Stripe account.
- Ensure You Are in Test Mode:
- Look for the toggle switch at the top right corner of the dashboard. Make sure it says “View test data”. If it says “View live data,” click on it to switch to test mode.
- Navigate to the Payments Section:
- In the left sidebar, click on “Payments.”
- This will take you to the Payments section, where you can explore various card payment options.
- View Supported Card Networks:
- In the Payments section, you will see a list of supported card networks, such as Visa, Mastercard, American Express, Discover, and more.
- Click on each card network to view additional details and test scenarios.
- Explore Test Card Numbers:
- For each card network, Stripe provides specific test card numbers that you can use to simulate transactions.
- Some commonly used test card numbers are Visa
- Use any future expiration date (e.g., 12/34) and any CVC (e.g., 123).
- Understand Card Attributes:
- Each card network has specific attributes, such as brand, funding (credit/debit), country, last4 digits, and more.
- Explore these attributes to understand how they are represented in the Stripe API and how they can be used in your application.
- Check Payment Intents and Charges:
- When you use test card numbers, Stripe creates payment intents and charges in test mode.
- You can view these test payment intents and charges by navigating to the respective sections in the left sidebar.
- Analyze the response data to understand the structure and attributes of payment intents and charges.
- Experiment with Test Scenarios:
- Stripe provides various test scenarios to simulate different payment outcomes, such as successful payments, declined transactions, and more.
- Explore these scenarios by using specific test card numbers or by manipulating the payment intent or charge data.
Follow these Steps To Implement The Integration In Salesforce
- Defined the Class and Method:
- Created a class named PaymentController.
- Defined a static method makePayment that takes an Integer parameter amount.
- Marked the method as @AuraEnabled to allow it to be called from Lightning Web Components.
- Fetched Payment Credentials from Custom Metadata:
- Used the Payment_Credentials__mdt custom metadata type to store the Stripe API keys.
- Fetched the secret key and public key from the custom metadata record with the label ‘Payment_Keys’.
- Prepared the HTTP Request:
- Set the API endpoint URL to ‘https://api.stripe.com/v1/charges’.
- Created instances of HttpRequest, HttpResponse, and Http.
- Defined the request body with the necessary parameters:: Encoded the
- Set the request method to ‘POST’.
- Set the request body with the prepared parameters.
- Set Authorization and Content-Type Headers:
- Constructed the Authorization header by concatenating ‘Basic ‘ with the base64-encoded string of secretKey + ‘:’ + publicKey.
- Set the ‘Authorization’ header with the constructed value.
- Set the ‘Content-Type’ header to ‘application/x-www-form-urlencoded’.
- Sent the HTTP Request and Handled the Response:
- Used the HTTP instance to send the request and get the response.
- Checked the response status code
- Handled Exceptions:
- Wrapped the code in a try-catch block to catch any exceptions.
- In the catch block, print the exception message and line number using System.debug
- Threw an AuraHandledException with an error message.
Additional Steps Taken (Not Shown in the Code)
- Set Up Remote Site Settings:
- Likely added the Stripe API URL (‘https://api.stripe.com’) as a remote site in Salesforce to allow outbound HTTP callouts.
- Tested the Integration:
- Tested the make payment method with various amounts and verified the response.
- Used Stripe’s test card numbers to simulate successful and failed payments.
- Deployed to Org:
- Once testing was complete, deployed the PaymentController class to the org environment.
Steps To Use Payment Integration In LWC Using Apex
- Imported Necessary Dependencies:
- Imported LightningElement from lwc to create a Lightning Web Component.
- Imported makePayment from @salesforce/apex/PaymentController.makePayment to call the Apex method for payment processing.
- Imported ShowToastEvent from lightning/platformShowToastEvent to display toast messages.
- Defined Component Properties:
- cardHolderName: Holds the cardholder name, initially set to ‘John’.
- paymentAmount: Holds the payment amount, initially set to 50.
- isSuccess: A boolean variable to track if the payment was successful.
- Implemented the handleCardHolderChange Method:
- This method is called when the cardholder name input changes.
- It updates the cardHolderName property with the new value from the event target.
- It checks if the cardholder name length is less than 3 characters.
- If the name is invalid, it calls the showToast method to display an error message.
- Implemented the handlePaymentChange Method:
- This method is called when the payment amount input changes.
- It updates the paymentAmount property by parsing the new value from the event target to an integer.
- It checks if the payment amount is less than 50.
- If the amount is invalid, it calls the showToast method to display an error message.
- Implemented the handlePayClick Method:
- This method is called when the “Pay” button is clicked.
- It checks if the card holder name is valid (length >= 3).
- It checks if the payment amount is valid (>= 50).
- If both are valid, it calls the submitPayment method with the payment amount multiplied by 100 (to convert from INR to paise).
- Implemented the submitPayment Method:
- This method is responsible for submitting the payment to the Apex class.
- It calls the makePayment Apex method, passing the payment amount as a parameter.
- If the payment is successful, it updates the isSuccess property to true and displays a success toast message.
- If an error occurs, it displays an error toast message.
- Implemented the showToast Method:
- This method is used to display toast messages on the UI.
- It dispatches a ShowToastEvent with the provided title, message, variant (success/error), and mode (dismissible).
Method Parameters
- handleCardHolderChange(event): Accepts an event parameter, which contains the new card holder name value from the input field.
- handlePaymentChange(event): Accepts an event parameter, which contains the new payment amount value from the input field.
- handlePayClick(event): Accepts an event parameter, which is the click event from the “Pay” button.
- submitPayment(amount): Accepts an amount parameter, which is the payment amount multiplied by 100 (to convert from INR to paise).
- showToast(title, message, variant, mode): Accepts title, message, variant, and mode parameters to configure the toast message.
How the Steps Work
- The user interacts with the input fields for card holder name and payment amount, triggering the handleCardHolderChange and handlePaymentChange methods respectively.
- When the user clicks the “Pay” button, the handlePayClick method is called.
- The handlePayClick method validates the card holder name and payment amount.
- If both are valid, it calls the submitPayment method with the payment amount multiplied by 100.
- The submitPayment method calls the makePayment Apex method, passing the payment amount as a parameter.
- If the payment is successful, it updates the isSuccess property to true and displays a success toast message using the showToast method.
- If an error occurs during the payment process, it displays an error toast message using the showToast method.
PaymentIntegration.html
<template>
<!--Defining Lightning Card To Display Payment Details And Card Details-->
<lightning-card title="Payment">
<!--If isSuccess Is False Then It Will Show The Payment UI-->
<template if:false={isSuccess}>
<!--Defining Payment Card For Payment Details-->
<div class="paymentCard">
<center>
<h1 class="paymentHeading"><strong>Payment Details</strong></h1>
</center>
<div class="cardDetails">
<h1><strong>Card Information</strong></h1><br>
<span class="visaLogo"><img src="https://techmatrixconsulting-ec-dev-ed--c.develop.vf.force.com/resource/1726554872000/Visa?" height="20px" width="30px"/></span>
<lightning-input label="Card Number" value="4242 4242 4242 4242" disabled="true"></lightning-input><br>
<lightning-input label="Card Expiration" value="12 / 24" disabled="true"></lightning-input><br>
<span class="visaLogo"><img src="https://techmatrixconsulting-ec-dev-ed--c.develop.vf.force.com/resource/1726555177000/Cvv?" height="20px" width="30px"/></span>
<lightning-input label="Card CVV" value="329" disabled="true"></lightning-input><br>
<lightning-input label="Card Holder Name" value="John" onchange={handleCardHolderChange}></lightning-input><br>
</div><br>
<div class="amountDetails">
<h1><strong>Payment Amount</strong></h1><br>
<span class="visaLogo">₹</span>
<lightning-input label="Amount" value="50" onchange={handlePaymentChange}></lightning-input><br>
</div>
<center>
<button class="payBtn" onclick={handlePayClick}>Pay</button>
</center>
</div>
<center>
<h1><strong>Note : Please Make Payment Of Atleast 50 Rupees.</strong></h1>
</center>
</template>
<!--If isSuccess Is True Then It Will Show The Success Payment UI-->
<template if:true={isSuccess}>
<div class="paymentSuccessCard">
<center>
<img src="https://techmatrixconsulting-ec-dev-ed--c.develop.vf.force.com/resource/1726565715000/Payment?" height="150px" width="150px">
</center>
<h1><strong>Payment Successful</strong></h1><br>
<h2><strong>Payment Of ₹{paymentAmount} Has Been Done Successfully.</strong></h2>
</div>
</template>
</lightning-card>
</template>
PaymentIntegration.js
import { LightningElement } from 'lwc';
import makePayment from '@salesforce/apex/PaymentController.makePayment';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
/*
@Name : PaymentIntegration
@Author : Himanshu Sharma
@Description : This Class Is Implemented To Make Payment
@Date : 17/09/2024
*/
export default class PaymentIntegration extends LightningElement {
cardHolderName = 'John';//Initial Card Holder Name
paymentAmount = 50;//Variable For Payment Amount
isSuccess = false;//Boolean Variable To Show The UI Component When Payment Get Successful
/*
* @description : This Method Handles The Change In The Card Holder Name And Show Warning If Card Holder Name Is Not Valid
* @return : This Method Does Not Return Anything
*/
handleCardHolderChange(event)
{
this.cardHolderName = event.target.value;//Fetching Card Holder Name From UI
if(this.cardHolderName.length <3)//Verifying Valid Card Holder Name
{
this.showToast('Invalid Name','Please Enter Atleast 3 Characters In Card Holder Name','Error','Dismissible');
}
}
/*
* @description : This Method Handles The Change In The Payment Amount And Show Warning If Payment Amount Is Not Valid
* @return : This Method Does Not Return Anything
*/
handlePaymentChange(event)
{
this.paymentAmount = parseInt(event.target.value);//Parsing Payment Amount To Integer From String
if(this.paymentAmount<50)//To Avoid The Failure Of Payment Verifying About The Payment Amount Should More Then 50
{
this.showToast('Invalid Payment Amount','Please Enter Amount 50 or More Than 50.','Error','Dismissible');
}
}
/*
* @description : This Method Handles The Click On The Pay Button And Show Warning If Payment Amount Is Not Valid And Card Holder Name Is Not Valid
* @return : This Method Does Not Return Anything
*/
handlePayClick(event)
{
if(this.cardHolderName.length <3)//Varifying Card Holder Name
{
this.showToast('Invalid Name','Please Enter Atleast 3 Characters In Card Holder Name','Error','Dismissible');
}
if(this.paymentAmount<50)//Veryfying Payment Amount
{
this.showToast('Invalid Payment Amount','Please Enter Amount 50 or More Than 50.','Error','Dismissible');
}
if(this.cardHolderName.length>=3 && this.paymentAmount>=50)//Submitting Payment To The Apex Class With Verification
{
this.submitPayment(this.paymentAmount*100);//Calls The Another Method To Submit Payment
}
}
/*
* @description : This Method Submits The Payment To Apex Class For Further Processing
* @return : This Method Does Not Return Anything
*/
submitPayment(amount)
{
makePayment({amount : amount})//Submitting Request To Apex
.then(result=>{
this.showToast('Payment Success','Payment Of Amount '+this.paymentAmount+' Has Been Done.','Success','Dismissible');
this.isSuccess = true;//Updating Boolean Variable To True For Payment Success Message
})
.catch(error=>{
this.showToast('Error Processing Payment','Due To Some Error Payment Cannt Be Processed','Error','Dismissible');
})
}
/*
* @description : This Method Displays The Toast Message On UI
* @return : This Method Does Not Return Anything
*/
showToast(title, message, variant, mode) {
this.dispatchEvent(new ShowToastEvent({
title,
message,
variant,
mode
}));
}
}
Apex Class
public class PaymentController {
/*
* @description : This Method Makes The Payment For Given Amount
* @return : This Method Returns The String Of Response
*/
@AuraEnabled
public static String makePayment(Integer amount)
{
try{
//Fetching Custom Metadata For Credentials
Payment_Credentials__mdt credentials = Payment_Credentials__mdt.getInstance('Payment_Keys');
String secretKey = credentials.Secret_Key__c;//Secret Key For Stripe Payment Integration
String publicKey = credentials.Public_Key__c;//Public Key For Integration
String apiURL = 'https://api.stripe.com/v1/charges';//Endpoint URL
HttpRequest request = new HttpRequest();
HttpResponse response = new HttpResponse();
Http httpRequest = new Http();
//Defining Body With Required Parameters
String requestBody = 'amount='+EncodingUtil.urlEncode(String.valueOf(amount),'UTF-8')+'¤cy='+EncodingUtil.urlEncode('inr','UTF-8')+'&source='+EncodingUtil.urlEncode('tok_visa','UTF-8');
request.setEndpoint(apiURL);
request.setMethod('POST');
request.setBody(requestBody);
//Defining Headers For Authorization And Content Type
request.setHeader('Authorization','Basic '+EncodingUtil.base64Encode(Blob.valueOf(secretKey+':' +publicKey)));
request.setHeader('Content-Type', 'application/x-www-form-urlencoded');
response = httpRequest.send(request);
//Verifying Status Code
if(response.getStatusCode() == 200)
{
return response.getBody();//Returning Response Body
}
else if (response.getStatusCode() != 200) {
throw new AuraHandledException('Error Processing Payment From Apex');
}
}
Catch(Exception e)
{
System.debug('Exception Message : '+e.getMessage());
System.debug('Exception Line Number : '+e.getLineNumber());
throw new AuraHandledException('Error Processing Payment From Apex');//Throwing Exception If Error Occured
}
return '';
}
}