DEV Community

Sabir Sheikh
Sabir Sheikh

Posted on

Accept Payments in Salesforce: A Complete Guide to Stripe Integration

Accept Payments in Salesforce: A Complete Guide to Stripe Integration

Tired of switching between your Salesforce CRM and a separate payment processor? What if you could accept credit card payments directly inside Salesforce and have every transaction automatically logged?

This guide will walk you through building a complete, secure payment gateway using Stripe and a Lightning Web Component (LWC). We'll cover everything: backend logic, frontend UI, security best practices, and deployment.

Prerequisites

Before you start, make sure you have:

  • A Salesforce Developer Org or Scratch Org.
  • A free Stripe Account.
  • Visual Studio Code with the Salesforce Extension Pack installed.

Step 1: Get Your Stripe API Keys

First, we need to get the credentials from Stripe to allow Salesforce to communicate with it.

  1. Log in to your Stripe Dashboard.
  2. Toggle the Test Mode switch in the top-left corner. This lets you make fake payments without charging real cards.
  3. In the left-hand menu, go to Developers > API keys.
  4. You will see two keys we need:
    • Publishable key: Starts with pk_test_.... This is safe to use in your frontend code.
    • Secret key: Starts with sk_test_.... Treat this like a password! Never expose it in frontend code. We will secure this in Salesforce.

Copy both keys and keep them handy.


Step 2: Create the Salesforce Data Model

We need a place to store the record of each successful payment.

  1. In Salesforce Setup, go to Object Manager > Create > Custom Object.
  2. Fill in the details:
    • Label: Payment Transaction
    • Plural Label: Payment Transactions
    • Object Name: Payment_Transaction__c
  3. Click Save.
  4. Go to the Fields section for your new object and click New. Create the following three fields:
    • Field 1:
      • Data Type: Text
      • Field Label: Payment ID
      • Field Name: Payment_ID__c
      • Length: 255
    • Field 2:
      • Data Type: Text
      • Field Label: Status
      • Field Name: Status__c
      • Length: 50
    • Field 3:
      • Data Type: Currency
      • Field Label: Amount
      • Field Name: Amount__c
      • Decimal Places: 2

Step 3: Secure the Connection with Named Credentials

This is the most important security step. We will store the Secret Key in a Named Credential so it's encrypted and never visible in your code.

  1. In Salesforce Setup, go to Security > Named Credentials.
  2. Click New Named Credential.
  3. Fill in the form as follows:
    • Label: Stripe_Named_Credential
    • Name: Stripe_Named_Credential (this will auto-fill)
    • URL: https://api.stripe.com
    • Identity Type: Named Principal
    • Authentication Protocol: Password Authentication
    • Username: Leave this blank.
    • Password: Paste your Stripe Secret Key (sk_test_...).
    • Check the box for Allow Merge Fields in HTTP Header.
  4. Click Save.

Step 4: The Apex Controller (Backend Logic)

This Apex class will receive the payment information from our LWC, communicate with Stripe using the Named Credential, and create a Payment_Transaction__c record on success.

  1. In VS Code, create a new Apex class named PaymentController.cls.
  2. Paste the following code:
// File: force-app/main/default/classes/PaymentController.cls
public with sharing class PaymentController {

    @AuraEnabled(cacheable=false)
    public static String processPayment(Decimal amount, String stripeToken) {
        // The 'callout:' prefix tells Salesforce to use the Named Credential for authentication.
        String endpoint = 'callout:Stripe_Named_Credential/v1/charges';

        Http http = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint(endpoint);
        req.setMethod('POST');

        // Stripe requires the amount in cents (e.g., $50.00 -> 5000)
        Integer amountInCents = (Integer)(amount * 100);

        // Set the request body with the amount, currency, and the token from the frontend
        req.setBody('amount=' + amountInCents + '&currency=usd&source=' + stripeToken);

        try {
            HttpResponse res = http.send(req);

            // Deserialize the JSON response from Stripe
            Map<String, Object> responseMap = (Map<String, Object>) JSON.deserializeUntyped(res.getBody());

            if (res.getStatusCode() == 200 && (String)responseMap.get('status') == 'succeeded') {
                // Payment was successful, create a record in Salesforce
                Payment_Transaction__c txn = new Payment_Transaction__c(
                    Payment_ID__c = (String)responseMap.get('id'),
                    Status__c = (String)responseMap.get('status'),
                    Amount__c = amount
                );
                insert txn;

                // Return a success message with the Salesforce Record ID
                return 'SUCCESS: Payment recorded with ID ' + txn.Id;
            } else {
                // Payment failed, return the error message from Stripe
                return 'ERROR: ' + (String)responseMap.get('error_message');
            }
        } catch (Exception e) {
            // Handle any other exceptions (e.g., network issues)
            return 'ERROR: An unexpected error occurred - ' + e.getMessage();
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Configure CSP Trusted Sites

For security, Salesforce blocks external scripts. We must whitelist Stripe's JavaScript library.

  1. In Salesforce Setup, go to Security > CSP Trusted Sites.
  2. Click New Trusted Site.
  3. Fill in the details:
    • Trusted Site Name: Stripe_JS_CDN
    • Trusted Site URL: https://js.stripe.com
    • Active: Check this box.
    • CSP Directives: Check the box for Allow JavaScript Connectors.
  4. Click Save.

Step 6: The Lightning Web Component (Frontend)

This is the user-facing part. We will create a single LWC that securely displays the payment form.

Part A: Create the Static Resource for Stripe.js

  1. Go to https://js.stripe.com/v3/.
  2. Save the page as stripe.js to your computer.
  3. In VS Code, right-click the force-app/main/default/staticresources folder and select SFDX: Create Static Resource.
  4. Name: stripe
  5. Cache Control: Public
  6. Browse and select the stripe.js file you just saved.
  7. Click Save.

Part B: Create the LWC

  1. In VS Code, right-click the lwc folder and select SFDX: Create Lightning Web Component.
  2. Name it stripePaymentForm.

Part C: Write the Code

Now, replace the contents of the three generated files with the code below.

stripePaymentForm.html

<template>
    <lightning-card title="Make a Payment" icon-name="standard:payment">
        <div class="slds-m-around_medium">
            <form id="payment-form">
                <div id="card-element" class="slds-p-around_small slds-box">
                    <!-- A Stripe Element will be securely inserted here. -->
                </div>
                <button id="submit-button" class="slds-button slds-button_brand slds-m-top_small" onclick={handlePayClick}>
                    Pay $50.00
                </button>
                <div id="card-errors" role="alert" class="slds-m-top_small slds-text-color_error"></div>
            </form>
        </div>
    </lightning-card>
</template>
Enter fullscreen mode Exit fullscreen mode

stripePaymentForm.js

// File: force-app/main/default/lwc/stripePaymentForm/stripePaymentForm.js
import { LightningElement } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import processPayment from '@salesforce/apex/PaymentController.processPayment';
import { loadScript } from 'lightning/platformResourceLoader';
import STRIPE_JS from '@salesforce/resourceUrl/stripe';

export default class StripePaymentForm extends LightningElement {
    stripe;
    cardElement;
    // Replace with your Stripe TEST Publishable Key
    stripePublishableKey = 'pk_test_...'; // <-- PASTE YOUR KEY HERE
    amount = 50.00; 

    renderedCallback() {
        if (this.stripe) {
            return; // Prevents script from being loaded multiple times
        }
        loadScript(this, STRIPE_JS)
            .then(() => {
                this.initializeStripe();
            })
            .catch(error => {
                console.error('Error loading Stripe.js:', error);
                this.showToast('Error', 'Could not load payment form.', 'error');
            });
    }

    initializeStripe() {
        this.stripe = window.Stripe(this.stripePublishableKey);
        const elements = this.stripe.elements();

        this.cardElement = elements.create('card', {
            style: {
                base: {
                    fontSize: '16px',
                    color: '#424770',
                },
            },
        });

        this.cardElement.mount('#card-element');

        this.cardElement.on('change', ({ error }) => {
            const displayError = this.template.querySelector('#card-errors');
            if (error) {
                displayError.textContent = error.message;
            } else {
                displayError.textContent = '';
            }
        });
    }

    async handlePayClick() {
        const submitButton = this.template.querySelector('#submit-button');
        submitButton.disabled = true;

        const { token, error } = await this.stripe.createToken(this.cardElement);

        if (error) {
            const errorElement = this.template.querySelector('#card-errors');
            errorElement.textContent = error.message;
            submitButton.disabled = false;
        } else {
            processPayment({ amount: this.amount, stripeToken: token.id })
                .then(result => {
                    if (result.startsWith('SUCCESS')) {
                        this.showToast('Success!', 'Payment was successful.', 'success');
                        this.cardElement.clear(); // Clear the form
                    } else {
                        this.showToast('Payment Failed', result, 'error');
                    }
                })
                .catch(apexError => {
                    this.showToast('Apex Error', apexError.body.message, 'error');
                })
                .finally(() => {
                    submitButton.disabled = false;
                });
        }
    }

    showToast(title, message, variant) {
        this.dispatchEvent(new ShowToastEvent({
            title: title,
            message: message,
            variant: variant,
        }));
    }
}
Enter fullscreen mode Exit fullscreen mode

stripePaymentForm.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>58.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>
Enter fullscreen mode Exit fullscreen mode

Step 7: Deploy and Add to Your Home Page

You're ready to see it in action!

  1. Deploy: In VS Code, open the Command Palette (Ctrl+Shift+P) and run SFDX: Deploy Source to Org.
  2. Create a Home Page:
    • In Salesforce Setup, go to Lightning App Builder.
    • Click New.
    • Select Home Page and click Next.
    • Give it a name like "Payment Home" and click Next.
    • Click Finish.
  3. Add Your Component:
    • On the left side, under "Standard Components," find your stripePaymentForm component.
    • Drag it onto the page canvas.
  4. Save and Activate:
    • Click Save.
    • You will be taken to the activation screen. Select "App Default" and choose an app (e.g., "Sales").
    • Click Save, then Activate.

Now, navigate to the Home tab in the app you selected. You will see your fully functional Stripe payment form! You can test it with the Stripe test card number: 4242 4242 4242 4242.

Top comments (0)