Salesforce CRM integration — bidirectional sync, case management, webhooks, bulk operations, SOQL queries
Scanned 9/6/2026
Install to Claude Code
npx -y skills add ArieGoldkin/claude-forge --skill salesforce-integration-patterns --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Salesforce Integration Patterns?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ariegoldkin-salesforce-integration-patterns)More formats (shields.io, HTML) on the badges page.
---
name: salesforce-integration-patterns
description: "Salesforce CRM integration — bidirectional sync, case management, webhooks, bulk operations, SOQL queries"
effort: low
paths:
- "**/*salesforce*"
- "**/*sfdc*"
keep-coding-instructions: true
---
# Salesforce Integration Patterns
Production patterns for Salesforce CRM ↔ application backend integration (AWS Lambda, Python).
## Quick Start
### Client Setup
Use a global Salesforce client with Secrets Manager authentication:
```python
# utils/salesforce_client.py
from simple_salesforce import Salesforce
from aws_lambda_powertools import Logger
import boto3, json, os
class SalesforceClient:
def __init__(self):
self._client = None
self._secrets = boto3.client('secretsmanager')
@property
def client(self):
if not self._client:
creds = json.loads(self._secrets.get_secret_value(
SecretId=os.getenv("SALESFORCE_SECRET_NAME")
)["SecretString"])
self._client = Salesforce(**creds)
return self._client
sf_client = SalesforceClient()
```
### User Sync Pattern
Upsert application users to Salesforce Contacts using an external ID custom field:
```python
# Check + upsert pattern.
# SOQL has no bind-parameter API in simple_salesforce, so the value is
# interpolated — VALIDATE it first to prevent SOQL injection. user.id is your
# own PK, so a strict allowlist is both safe and sufficient.
import re
user_ext_id = str(user.id)
if not re.fullmatch(r"[A-Za-z0-9_-]+", user_ext_id):
raise ValueError("unexpected External_User_ID format")
existing = sf_client.client.query(
f"SELECT Id FROM Contact WHERE External_User_ID__c = '{user_ext_id}'"
)
# Tip: prefer upsert-by-external-id to skip the query+branch entirely:
# sf_client.client.Contact.upsert(f"External_User_ID__c/{user_ext_id}", sf_data)
sf_data = {
"Email": user.email,
"External_User_ID__c": user.id,
"User_Status__c": user.status,
"Subscription_Status__c": user.subscription.status
}
if existing["totalSize"] > 0:
sf_client.client.Contact.update(existing["records"][0]["Id"], sf_data)
else:
sf_client.client.Contact.create(sf_data)
```
## Integration Workflows
### User Lifecycle Events
```
user.created → Create Salesforce Contact
user.updated → Update Contact fields
subscription.started → Update Subscription_Status__c
subscription.cancelled → Update status + Create support Case
```
### Case Management
```
Salesforce Case → Webhook → API Gateway → Lambda → App DB
```
- Verify HMAC-SHA256 signature (`X-SF-Signature` header)
- Store case in application DB with `sf_case_id` reference
- Notify user via SES or notification channel
### Bulk Sync
```
CloudWatch (nightly) → Fetch active users → Salesforce Bulk API (upsert)
```
- Use `bulk.Contact.upsert()` for >200 records
- External ID: `External_User_ID__c`
- Batch size: 200
## Custom Salesforce Fields
Required on Contact object (rename fields to match your domain):
- `External_User_ID__c` (Text, External ID, Unique) — your application's user ID
- `User_Status__c` (Picklist: active, inactive, churned)
- `Subscription_Status__c` (Picklist: trial, active, cancelled, expired)
- `Tags__c` or `Segments__c` (Multi-Picklist) — domain-specific categorization
- `Last_Sync_Date__c` (DateTime)
## Security Notes
- **SOQL injection**: SOQL has no bind-parameter API in `simple_salesforce`; any value interpolated into a query string must be validated/escaped first (see the User Sync pattern above). Prefer upsert-by-external-id over query-then-branch where possible.
- **Webhook authenticity**: verify the `X-SF-Signature` HMAC-SHA256 on inbound Case webhooks before trusting the payload.
- **Least privilege**: scope the integration user's profile to only the objects/fields it syncs.
## Adopting for Your Domain
Rename `External_User_ID__c`, `User_Status__c`, and `Tags__c` to match your domain's terminology (e.g., `Account_ID__c`, `Patient_ID__c`, `Customer_ID__c`). The patterns (upsert by external ID, HMAC webhook verification, Bulk API with >200 records) remain the same regardless of domain.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!