# Salesforce Destination

> Source: https://docs.trailspark.ai/destinations-rules/salesforce-destination

## Overview

The Salesforce destination writes evaluation results to your Salesforce Lead, Contact, and Account objects. Trailspark maps scores, reasoning, and evaluation dates to custom fields you define in Salesforce, and optionally pushes buying-group coverage and role data when you enable that section.

## Prerequisites

- Salesforce integration connected (**Settings** > **CRM Integration** > **Connect** tab)
- Custom fields created in Salesforce for Trailspark data
- **Admin** or **Owner** role in Trailspark
- Field-level security in Salesforce allowing write access

## Custom Fields in Salesforce

Create these custom fields on both the Lead and Contact objects:

| Field Label | Suggested API Name | Data Type |
| - | - | - |
| Trailspark Score | `TrailSpark_Score__c` | Text, or Picklist containing Hot, Warm, Cold |
| Trailspark Evaluation Date | `TrailSpark_Evaluation_Date__c` | DateTime |
| Trailspark Reasoning | `TrailSpark_Reasoning__c` | Long Text Area |

For account propensity, create on the Account object:

| Field Label | Suggested API Name | Data Type |
| - | - | - |
| Trailspark Propensity | `TrailSpark_Propensity__c` | Text (values: high\_propensity, medium\_propensity, low\_propensity) |
| Trailspark ICP | `TrailSpark_ICP__c` | Text (the ICP name the account was scored against) |
| Trailspark Score status | `TrailSpark_Score_Status__c` | Text (values: current, retired, not\_evaluated) |
| Trailspark AI Reasoning | `TrailSpark_Account_Reasoning__c` | **Long Text Area** (see the warning below) |

To store the ICP or Score status on Lead or Contact records too, create matching Text fields (for example `TrailSpark_ICP__c` and `TrailSpark_Score_Status__c`) on those objects.

Buying-group fields are documented in the section below — add them only if you plan to use that feature.

## Configuration

Go to **Settings** > **CRM Integration** > **Destinations** tab.

### Destination Settings

- **Send Evaluations to Salesforce** -- Toggle to enable/disable the destination
- **Salesforce Integration** -- Select which connected Salesforce instance to use
- **Create Records if Not Found** -- When enabled, Trailspark creates new Lead or Contact records if no match exists. You can filter which score levels trigger creation (Hot, Warm, Cold)

### Field Mapping

The field mapping section has two tabs: **Lead Object** and **Contact Object**. For each, map three required fields:

| UI Label | Description |
| - | - |
| **Score Field** | Where the evaluation score is stored |
| **Evaluation Date Field** | Where the evaluation timestamp is stored |
| **Reasoning Field** | Where the AI reasoning is stored |
| **ICP** | Where the name of the ICP the record was scored against is stored (optional) |
| **Score status** | Where the account's score status (current, retired, or not evaluated) is stored (optional) |

Trailspark loads your Salesforce field metadata automatically. Select fields from the dropdown — fields appear with both their label and API name.

#### Field types

- **Score Field** — use a **Text** field, or a **Picklist** whose values are **Hot**, **Warm**, and **Cold**. Trailspark writes the score with a capital first letter, exactly as shown. A restricted picklist that doesn't contain those three values rejects the write, and because Salesforce updates a record in a single write, that takes the whole record with it — the evaluation date, the reasoning, and the buying-group fields too, not just the score.
- **Evaluation Date Field** — use a **DateTime** field.
- **Reasoning Field** — use a **Long Text Area** field. Salesforce's default Text field holds 255 characters, which is smaller than most explanations, and an over-length value fails the whole record the same way.

> [!NOTE]
> If you created your score picklist with lowercase values (`hot`, `warm`, `cold`), add **Hot**, **Warm**, and **Cold** to it — or switch the field to Text. Earlier versions of Trailspark wrote the lowercase form to Salesforce; every destination now writes the capitalized form, matching what HubSpot and Airtable have always received.

### Account Propensity Score

The propensity score card configures where account-level propensity (high/medium/low) is written:

- **Account Propensity Field** (primary) -- Written to the Account object when a linked Account exists
- **Lead Propensity Field** (fallback) -- Written to the Lead object when no Account is linked

Both fields are optional.

### ICP

The **ICP** card configures where the name of the ICP each account was scored against is written on the Account. It travels on the same account-level sync as the propensity score, so a Salesforce automation or flow can branch on *which* ICP produced a score. The field is optional. When an account was scored without a specific ICP, nothing is written.

### AI reasoning

The **AI reasoning** card configures where each account's plain-language explanation is written on the Account — the same narrative you see on the account in Trailspark and in Slack alerts. It travels on the same account-level sync as the propensity score and always describes that score, so the two can never disagree.

Map it when you want reps to read *why* an account is hot without leaving Salesforce — on the Account record, in a list view, in a report, or in a meeting sidebar. This is separate from the Lead/Contact-level **Reasoning Field**, which explains an individual person's score; map either, both, or neither.

> [!WARNING]
> Use a **Long Text Area** field, not **Text**. Salesforce's default Text field holds 255 characters, which is smaller than most explanations — and because Salesforce updates a record in a single write, a field that is too small rejects **the whole update**, taking the propensity score and buying-group fields with it, not just the reasoning.

The field is optional. When an account's evaluation has no explanation, nothing is written — your existing field value is left untouched rather than blanked. When an account's score is retired, the last explanation stays in place and **Score status** flips to `retired`.

### Score status

The **Score status** card configures where each account's score status is written on the Account (and, on the Lead and Contact tabs, on those records). It travels on the same sync as the propensity score and takes one of three values:

- **current** -- the pushed propensity score reflects the account's live standing.
- **retired** -- the account no longer matches the ICP it was scored against, so its last pushed score is stale and should no longer be trusted.
- **not\_evaluated** -- the account has no evaluation yet.

When an account leaves the ICP it was scored against, Trailspark promptly updates this field to **retired** in Salesforce (for destinations that map it) — you don't have to wait for the account's next sync. Without the field, a retired account simply stops receiving score updates and its last pushed score silently goes stale, so a Salesforce flow cannot tell a fresh score from a stale one. Map it to let automations suppress or flag scores that are no longer current. The field is optional; unmapped, nothing is written.

## Enrichment Fields

The **Enrichment Fields** card writes data from your connected enrichment providers (for example Clay or Reo.dev) into Salesforce Account fields you choose. All fields are optional and only write when you map them.

| UI Label | Written to | What it contains |
| - | - | - |
| **Industry** | Account | Industry, from your enrichment provider(s) |
| **Employee Count** | Account | Employee count, from your enrichment provider(s) |
| **Region** | Account | Geographic region, from your enrichment provider(s) |
| **Market Segment** | Account | Market segment, from your enrichment provider(s) |
| **Website Domain** | Account | Website domain, from your enrichment provider(s) |

> [!TIP]
> Trailspark writes only enrichment-provider data into these fields -- never your Salesforce Account's own value, and never a blend of the two. A mapped field is left blank when there is no matched enrichment value; it is not filled from Salesforce.

This writes on the same account-level sync that pushes propensity and buying-group coverage, for accounts linked to a Salesforce Account record.

### Custom enrichment fields

If your enrichment provider sends fields beyond the standard five and you've turned them on under **Enriched fields** (see [Enrichment Rules & Budget Caps](https://docs.trailspark.ai/data-enrichment/enrichment-rules-and-budget-caps)), each active field gets its own extra row on this card, using the label you gave it. Map it to a Salesforce Account field the same way as the standard fields. Turning a field off later doesn't remove an existing mapping -- the row is kept and marked **"No longer active,"** and it stops writing until the field is reactivated.

## Account Fit & Outside Activity Fields

Two more cards write Trailspark's newer account-level facets to the Account object. Neither ever changes an account's propensity score — they're a separate read next to it. All four fields are optional and only write when you map them.

| UI Label | Written to | What it contains |
| - | - | - |
| **Account fit** | Account | How well the account's profile matches your ICP: `strong`, `partial`, `weak`, or `unknown` |
| **Outside activity** | Account | How recently third-party activity was seen on the account: `hot`, `warm`, `cold`, or `none` |
| **Last outside activity** | Account | The date of the most recent outside-activity event |
| **Outside activity kinds** | Account | A comma-separated list of what kind of outside activity was seen recently, e.g. "Raised funding, Hiring activity" |

Create **Last outside activity** as a **Date** field in Salesforce. The other three are Text fields.

`unknown` and `none` are written on purpose — they mean Trailspark looked and didn't find enough to grade, which is different from the field being untouched because nothing is mapped. See [Account detail](https://docs.trailspark.ai/accounts-dashboard/account-detail) for what these values mean on the account page.

These fields update whenever the account's other evaluation fields do (a new score, a coverage change, or the account leaving its ICP) — a change in outside activity by itself, with nothing else about the account changing, doesn't trigger its own push. If you need the freshest possible read, re-score the account or wait for its next scheduled evaluation.

## Buying Group Fields

Enable the **Push buying-group fields** toggle to push coverage and role data alongside evaluation scores. All fields in this section are optional — they write only when you map them.

### Contact properties

| UI Label | Written to | What it contains |
| - | - | - |
| **Buying-group roles (Lead)** | Lead object | The lead's assigned role names, semicolon-separated. Also used as the default for Contact records unless a Contact override is set. |
| **Buying-group roles (Contact override)** | Contact object | Optional. Overrides the Lead field for Contact records specifically. |
| **CRM Role Source Field** | Read from Contact | Trailspark reads this field from your Salesforce Contacts. Set it to a field where you've recorded a role; Trailspark uses it as the authoritative assignment. |

### Account properties

| UI Label | Written to | What it contains |
| - | - | - |
| **Buying-group stage** | Account | Dormant, Forming, or Complete |
| **Engagement completeness (%)** | Account | Share of required roles with an actively engaged person |
| **Known completeness (%)** | Account | Share of required roles with any person assigned |
| **People still needed** | Account | Count of additional people needed to complete the group |
| **Missing roles** | Account | Role names not yet filled (semicolon-separated) |
| **Engaged roles** | Account | Role names currently active (semicolon-separated) |
| **Propensity as-of date** | Account | Date the propensity score was last evaluated |
| **At-risk status** | Account | "At Risk" when high propensity meets stalled engagement; otherwise "Current" |
| **Renewal health** | Account | Health signal for renewal-ICP accounts: Healthy, Cooling, Fading, Cold, or Pending |

For what these values mean, see [Account coverage](https://docs.trailspark.ai/buying-groups/account-coverage).

> [!TIP]
> You do not need to map every buying-group field. Map only the ones you plan to act on in your Salesforce workflows or reports.

## Dual-Object Support

Salesforce stores people as Leads (unconverted) and Contacts (converted). Trailspark matches by email address and writes to whichever object the lead exists on. You configure field mappings independently for each object.

## Troubleshooting

| Issue | Resolution |
| - | - |
| Field not in dropdown | Verify the field exists on the correct object and field-level security allows API access |
| Data not writing | Check that the destination is enabled, integration is connected, and no Salesforce validation rules are blocking the update |
| Wrong record updated | Review duplicate records in Salesforce -- Trailspark matches by email |
| Buying-group fields not writing | Confirm the "Push buying-group fields" toggle is on and the field is mapped |

## Next Steps

- [HubSpot Destination](https://docs.trailspark.ai/destinations-rules/hubspot-destination)
- [Airtable Destination](https://docs.trailspark.ai/destinations-rules/airtable-destination)
- [Account coverage](https://docs.trailspark.ai/buying-groups/account-coverage) -- Understand the values being pushed
- [Salesforce integration overview](https://www.trailspark.ai/integrations/salesforce) — what the Salesforce integration does, the fields Trailspark writes, and how scoring uses your CRM data
