Salesforce implementation guide
Enrich Salesforce contacts through REST
Build a Salesforce contact enrichment workflow with TargetWise: field mapping, a dry-run example, record-change checks and controlled API updates.
Updated 10 September 2026 · Documentation and review policy
Start with a reviewed test contact.
- Create a named TargetWise workspace key.
- Use an OAuth access token for your Salesforce org, with API access and permission to read and update the Contact fields you select. Use the instance URL returned by your OAuth connection. Choose a supported version from
GET /services/data/; see the Salesforce REST resources. - Confirm that the name and company domain identify this CRM contact. The fictional record below must be replaced with your own approved test record.
- Download targetwise-crm.mjs beside your Node.js script. It proposes changes by default.
Read, enrich and inspect the proposed update.
import { enrichCrmContact } from './targetwise-crm.mjs';
const outcome = await enrichCrmContact({
platform: 'salesforce',
recordId: process.env.CRM_CONTACT_ID,
identity: {
"first_name": "Alex",
"last_name": "Reed",
"company_domain": "example.com"
},
targetwiseKey: process.env.TARGETWISE_API_KEY,
crmToken: process.env.CRM_ACCESS_TOKEN,
crmOrigin: process.env.SALESFORCE_INSTANCE_URL,
apiVersion: process.env.SALESFORCE_API_VERSION, // e.g. a version returned by /services/data/
includePhone: false,
apply: false,
});
// Inspect outcome.patch in your secure review interface.
// Log only status and request ID, not the contact values.
console.log(outcome.status, outcome.requestId);The helper reads the existing contact, skips a lookup when the requested fields are already filled, and calls POST /api/v1/contacts/enrich once. Phone retrieval is off by default. The lookup can consume your plan’s usage balance even when the CRM update is a dry run.
Keep trusted data and inspect unresolved fields.
| TargetWise field | Salesforce property | Write rule |
|---|---|---|
| data.work_email | Only when the existing value is empty and the returned identity was reviewed | |
| data.business_phone | Phone | Only if phone was requested; preserve the current value |
| data.phone_type | Do not infer MobilePhone | unknown is not a verified mobile classification |
| request_id | Your integration event log | Store for tracing without logging the result body |
{
"object": "enrichment_result",
"status": "partial",
"request_id": "illustrative-request",
"data": {
"work_email": "alex@example.com",
"business_phone": null
},
"unresolved_fields": [
"business_phone"
]
}A partial result may still contain the email you requested. A missing value never clears an existing CRM field. Add company enrichment as a separate, deliberate request when account context is needed; use reverse email lookup when the business email is your starting identifier.
Apply only after the test record passes review.
Set apply: true for your reviewed test run. The example re-reads the record and stops if its tracked fields changed. The Salesforce update also sends If-Unmodified-Since when LastModifiedDate is available; handle a precondition failure by reviewing the contact again.
- Test a missing email, an already-filled record, a partial response, no match and a record changed during the lookup.
- Stop on 400 or 401. Correct input or authentication. On 402, review balance. On 429, respect Retry-After and workspace limits; do not loop immediately.
- Store an integration event ID with the completed outcome. Check it before re-running the event; a repeated POST is not automatically free.
The downloadable mapping and orchestration example is covered by local fixture tests, including CRM HTTP requests. Run this checklist in your own CRM sandbox before enabling production writes. This guide does not install a native CRM connector.