Technical guide

Stripe technical guide

Everything an engineer needs to connect Stripe to Salesforce: architecture, the exact build steps with real code, field mapping, the data model, security, monitoring, and the pitfalls we design out.

Platform: StripeType: Payment gatewayDirection: Two-wayObjects: Account, Invoice, Payment, Case

The workhorse payment gateway across our Salesforce builds, from checkout and subscriptions to donations and reconciliation. We have shipped it across 16 client projects and 214 build tasks.

The value is what happens after the charge: matching payments to records, handling refunds, and keeping finance reconciled without manual work.

We build a hardened webhook pipeline: a public Apex REST endpoint on a Salesforce Site, signature verification on every event, and flows that turn raw Stripe events into clean, reconciled records.

Every Stripe build is delivered by a senior Salesforce architect on a fixed price, tested end to end in a sandbox, deployed to your org, and backed by 30 days of hypercare. You own the result: documented, source-controlled, and free of black-box middleware lock-in.

the connection at a glancesync active
01Stripe
02Salesforce Site
03Apex REST
04Events object
05Flows
06Records
Integration facts

How Stripe connects to Salesforce

The real connection surface: how it authenticates, what it is built on, the endpoints and events in play, and where the reference docs live.

Connects via
Managed package (AppExchange): Stripe app for Salesforce PlatformPre-built Flow invocable actions plus Apex (AgnosticInvocable for uncovered endpoints)Inbound Stripe webhooks logged to a Stripe Events object, then processed in Flow
Package
Stripe app for Salesforce Platform
Authentication
Stripe secret / restricted API key (Bearer) outbound; inbound webhooks verified with an HMAC-SHA256 endpoint signing secret via the Stripe-Signature header
API type
REST+Webhooks
https://api.stripe.com/v1

Key endpoints

/v1/checkout/sessions/v1/payment_links/v1/charges/v1/payment_intents/v1/customers

Webhook and platform events

checkout.session.completedcheckout.session.expiredcharge.succeededpayment_intent.succeededinvoice.paid
Free download

Build this with AI agents

Copy the full playbook as a prompt for any coding agent, or install it as a Claude Code skill. Either way your agent builds with our exact approach: the architecture, the Apex code, the field mapping, the rate limits, and the pitfalls to design out. Free, no signup.

Loading the Stripe playbook...
Paste into Claude Code, Cursor, or any coding agent
From our builds

What we build for a Stripe integration

Stripe wired into Salesforce across many orgs: pay-by-link buttons on Case and Account, Stripe webhook events handled in Flow, and an automated gift and donation capture that even creates Accounts for unknown donors.

14client projects
214delivery tasks shipped

Pay-by-link on the record

Stripe payment-link buttons on Case and Account and embedded in email templates, so staff collect payment without leaving Salesforce.

Webhook events handled in Flow

checkout.session.completed and charge.succeeded events captured and mapped to records with idempotent, replay-safe handling.

Gift and donation automation

A "Stripe Gift transaction" flow that creates gift and donation records, and creates Accounts for unknown donors on the fly.

Data hygiene and fixes

Diagnosed double-charge and event-mapping issues and backfilled payment methods that were missing a Stripe gateway.

Real components we ship

checkout.session.completed webhookcharge.succeeded webhook"Stripe Gift transaction" FlowPay-by-link on Case and AccountPayment links in email templatesPayment-method backfillDouble-charge diagnostics
Step 0

What you will need

What we confirm on both sides before writing a line of code.

A Salesforce edition with API access (Enterprise, Unlimited, or Developer)
A dedicated sandbox to build and test in
Stripe test-mode credentials to validate before going live
A Salesforce Site to host the public webhook endpoint
A Stripe account on a plan with API access
System Administrator access on both systems
A dedicated integration user with a minimum-access permission set
Agreement on the objects, fields, and sync direction for the Stripe data
How it works

From trigger to record, end to end

The production runtime flow, with what happens in each system.

runtime sequence5 steps
  1. 01

    Customer pays

    In Stripe

    A customer or donor pays through a Stripe payment link on a Case or Account, or a link embedded in an invoice or email.

    $Card data stays in Stripe; Salesforce only ever sees tokens and ids, keeping PCI scope low.
  2. 02

    Stripe fires a webhook

    In transit

    Events such as checkout.session.completed and charge.succeeded post to a secured Apex REST endpoint.

    $Delivered to a public /services/apexrest/ URL on a Salesforce Site.
  3. 03

    Verified and routed

    In Salesforce

    The controller verifies the signing secret, guards against duplicates and double-charges, and returns 200 fast.

    $Signature validated with the webhook secret; processing continues async in a Queueable.
  4. 04

    Records created or updated

    In Salesforce

    Flows create the payment or gift record and an Account for unknown donors, with Stripe ids stored.

    $Idempotent upsert on the event id via SalesforceStripeWebhooksController.
  5. 05

    Reconcile and report

    In Salesforce

    The payment is reconciled to the Account or invoice, methods are backfilled, and refunds flow back.

    $FetchAndUpdateStripePaymentBatch reconciles; RefundInvoiceFromStripeHelper handles refunds.
Architecture

How the data actually flows

Left to right: sources, the integration layer, Salesforce, and the outcomes it drives.

system architecture
Sources
Stripe Checkout
Payment Links
Webhook events
Chargent Anywhere
Integration layer
Webhook REST controller
Payment batch jobs
Record-triggered flows
Refund helper
Salesforce
Account
Invoice / Payment
Opportunity
Case
Outcomes
Auto-reconciled payments
Donation and gift records
Zero manual entry

// sources feed the integration layer, Salesforce persists, outcomes ship

Data model

The objects behind the integration

The Salesforce objects we read and write, what each one is for, and the fields that carry the load.

ObjectPurposeKey fields
PaymentThe primary Salesforce record Stripe data maps onto.External_Id__c, Name, Status
Inbound_Event__c (custom)Stores each raw event idempotently for audit and replay.Event_Id__c, Payload__c, Processed__c
AccountMatched or created for the customer or company behind the record.Name, External_Id__c
Error_Log__c (custom)Captures every request, response, and failure so anything can be replayed.Payload__c, Status__c, Related_Id__c

Salesforce objects typically in play for Stripe

Stripe Events (managed object)AccountContactOpportunityCase
Step by step

Build the Stripe integration

Every step we follow to ship a production-grade build, with the code that matters.

1

Plan the integration and prerequisites

We agree the events that matter and design a secure public endpoint before touching code.

  • A Salesforce edition with API access, a dedicated sandbox, and a Salesforce Site for the public URL
  • A Stripe account in test mode first, with admin access on both systems
  • The exact events, target objects, and reconciliation rules agreed up front
  • A hardened Site guest user with the absolute minimum permissions
2

Build the Apex REST endpoint

We give Stripe a typed, testable place to POST events.

  • An @RestResource class with an @HttpPost handler mapped to a stable URL
  • The raw request body is read once and kept for signature verification and audit
InboundWebhookResource.clsapex
@RestResource(urlMapping='/webhook/*')
global with sharing class InboundWebhookResource {
  @HttpPost
  global static void handle() {
    RestRequest req = RestContext.request;
    String raw = req.requestBody.toString();

    if (!WebhookSignature.isValid(raw, req.headers.get('X-Signature'))) {
      RestContext.response.statusCode = 401;      // reject unverified events
      return;
    }
    Inbound_Event__c e = new Inbound_Event__c(
      Event_Id__c = EventParser.idOf(raw), Payload__c = raw);
    upsert e Event_Id__c;                         // idempotent capture
    System.enqueueJob(new EventProcessor(e.Id));  // process asynchronously
    RestContext.response.statusCode = 200;         // respond fast
  }
}
3

Expose it securely on a Salesforce Site

We make the endpoint reachable without opening the whole org.

  • Create a Salesforce Site and enable only the one Apex class for the guest user
  • The public URL follows /services/apexrest/...; every other guest permission stays off

Watch out: lock down the guest user

A Salesforce Site runs as a guest user. Grant it access to only the one Apex class, or you expose far more of the org than a webhook ever should.

4

Register the webhook in Stripe

We subscribe to exactly the events we need, nothing more.

  • In the Stripe dashboard, add the endpoint URL and select the relevant events (checkout, charge, invoice, refund, and so on)
  • Copy the webhook signing secret into a protected custom setting or custom metadata
5

Verify signatures and prevent replay

We make sure only genuine, once-only events ever change data.

  • Compute an HMAC-SHA256 of the raw body with the signing secret and constant-time compare it
  • Reject on mismatch, and check the event timestamp to block replay attacks
WebhookSignature.clsapex
public class WebhookSignature {
  public static Boolean isValid(String rawBody, String header) {
    Blob secret = Blob.valueOf(WebhookConfig.signingSecret());
    Blob mac = Crypto.generateMac('HmacSHA256', Blob.valueOf(rawBody), secret);
    String expected = EncodingUtil.convertToHex(mac);
    // constant-time compare guards against timing attacks
    return ConstantTime.equals(expected, header);
  }
}

Watch out: verify every event

A public endpoint is a target. Validate the signing secret and make the handler idempotent, or a retried or spoofed event can double-post to your records.

6

Respond fast, process asynchronously

We never let processing block the webhook response.

  • Return HTTP 200 within the vendor timeout, which is usually only a few seconds
  • Hand the heavy work to a Queueable so slow processing never triggers a retry storm
EventProcessor.clsapex
public class EventProcessor implements Queueable {
  private Id eventId;
  public EventProcessor(Id eventId) { this.eventId = eventId; }

  public void execute(QueueableContext ctx) {
    Inbound_Event__c e = [SELECT Payload__c FROM Inbound_Event__c WHERE Id = :eventId];
    Map<String,Object> body = (Map<String,Object>) JSON.deserializeUntyped(e.Payload__c);
    // heavy work runs here, off the webhook thread: map onto Accounts, Cases, Payments
    EventRouter.route(body);
    update new Inbound_Event__c(Id = eventId, Processed__c = true, Processed_At__c = System.now());
  }
}
7

Capture raw events idempotently

We keep a durable, replayable record of everything received.

  • Upsert an Inbound_Event__c on the event id so duplicate deliveries are ignored
  • Store the raw JSON for audit and for replay if a downstream mapping ever changes
8

Map events onto your Payment

We turn raw Stripe events into clean Salesforce data.

  • Flows or triggers translate events onto Accounts, Payment, Payments, and Cases
  • Store the Stripe ids on the records and handle out-of-order events gracefully
9

Handle money and edge cases

We cover the cases that otherwise become disputes.

  • Reconcile payments, and handle refunds, chargebacks, and partial captures
  • Backfill missing data and alert on any mismatch before it reaches finance
10

Test, deploy, and monitor

We prove it end to end and keep watch in production.

  • Apex tests build a RestContext request and assert the resulting records; replay real test-mode events
  • Deploy via change sets, restrict the events object to admins, and monitor with error logging plus 30 days of support
Field mapping

Example field mapping

How Stripe data lands on your Salesforce records. We tailor the full mapping to your org.

StripeSalesforceNotes
Stripe charge idPayment.External_Id__cUnique external id, upsert key
Stripe amountPayment.Amount
Stripe currencyPayment.CurrencyIsoCode
Stripe customerAccountMatched or created
Stripe statusPayment.StatusPicklist value mapping
Created / updated atLastModifiedDateEnables delta sync and audit
Owner or repPayment.OwnerIdAssignment rules or a default owner
API & limits

Rate limits and governor limits

The platform constraints we design around, so the integration stays fast and never falls over at scale.

Specific to Stripe

Stripe API ~100 read + 100 write requests/sec live (25/sec test)
Webhook endpoints must return 2xx quickly or Stripe retries with backoff for up to ~3 days
Salesforce Apex callout limits: 100 callouts/transaction, 120s

Salesforce platform limits

A webhook handler must return within Stripe's timeout, usually a few seconds. We acknowledge with HTTP 200 immediately and process the event asynchronously.
Salesforce Sites have their own request limits. Heavy processing is offloaded to a Queueable so the public endpoint stays fast.
Stripe retries failed deliveries automatically. Idempotency on the event id means a retried event is never processed twice.
Security

Secure by design

How we keep the integration safe, least-privilege, and compliant.

Secrets stored in Named Credentials and permission sets, never in code or metadata
A least-privilege integration user, with field-level security and sharing scoped tight
All traffic over TLS, with signature verification on inbound events
Card data never touches Salesforce, keeping your PCI scope minimal
Shield Platform Encryption available for sensitive fields
A full audit trail: every request and response logged for traceability
Every automation runs as a dedicated integration user, so actions are attributable and revocable
Sandbox-first delivery and change-set deployment keep production changes reviewed and controlled
Monitoring

Monitoring, retries, and reliability

What keeps the integration trustworthy in production, and how you know the moment something needs attention.

Every request and response is logged to a custom Error Log object, tagged with the related record id.
Failed calls retry with exponential backoff; anything still failing lands in a dead-letter queue for review.
Idempotency keys guarantee a retried or duplicate event never double-posts a record.
A dashboard surfaces failures, latency, and volume so problems are caught before users notice.
Optional email or Slack alerts fire on repeated failures or a stalled sync.
Testing & deployment

How we test, deploy, and hand it over

The quality gates every build clears before it touches your production org.

Apex unit tests with HttpCalloutMock cover the success path, failure handling, and a 200-record bulk case, at 75 percent or higher coverage.
The full flow is validated in a sandbox against real sample data and the edge cases that matter.
A parallel run reconciles the integration against your live system before cutover.
Everything deploys through change sets or an SFDX and CI pipeline, under version control.
Permission sets, sharing, and Named Credentials are configured in production, then we run 30 days of monitored hypercare.
Pitfalls

Common pitfalls we design out

The mistakes that quietly break integrations, and how we avoid each one.

Missed or duplicated events

Verify signatures, upsert on the event id, and return 200 within the timeout.

Webhook times out on heavy processing

Acknowledge fast and process the event in a Queueable.

Guest user exposes too much

Grant the Site guest user access to only the single Apex class.

No visibility when it breaks

We log every call and surface failures on a dashboard with alerts, so an issue never goes unnoticed.

Reporting drifts from reality

External-id keys and a delta timestamp keep Salesforce and the source reconciled, so reports stay trustworthy.

Gotchas specific to Stripe

Each webhook endpoint has its own signing secret; a wrong or rotated secret silently fails verification
Events must be explicitly enabled and field-mapped to Salesforce objects or nothing syncs
Endpoints outside the API Extension pack require the AgnosticInvocable action
FAQ

Stripe integration: technical FAQs

How do you authenticate Stripe with Salesforce?

We connect Stripe using named credentials and API keys and store every secret in Salesforce Named Credentials with a permission set, so nothing is hard-coded or shipped in metadata.

Does the Stripe integration handle bulk volume?

Yes. All Apex is bulkified, volume moves to Queueable or Batch Apex, and we respect the Salesforce governor limits (SOQL, DML, and callout caps per transaction).

How do you prevent duplicate records?

We upsert on a unique external-id field, so a retried or duplicate payload is idempotent and never creates a second Payment.

How is the integration tested and deployed?

Apex tests with HttpCalloutMock cover the success, failure, and a 200-record bulk case (75 percent plus coverage). We deploy via change sets or an SFDX and CI pipeline.

What happens if Stripe or Salesforce is briefly down?

Failed calls retry with backoff and land in an Error Log object with alerting, so nothing is lost and any event can be replayed.

How do you secure the webhook endpoint?

The Apex REST endpoint runs on a Salesforce Site with a locked-down guest user, verifies the HMAC signature on every event, and checks the timestamp to block replays.

Want us to build your Stripe integration?

Skip the build. In a free 30-minute call we will map your Stripe flow and hand you a clear, fixed-price plan.

Ask me anything