> ## Documentation Index
> Fetch the complete documentation index at: https://docs.julian.11x.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Salesforce

> What to set up in Salesforce before connecting Julian, and how Julian reads and writes your Salesforce records.

Julian connects to Salesforce through Ampersand, a managed integration provider that brokers third-party connections
securely. The connection is authorized once for your whole organization and covers every Julian agent.

This page covers the Salesforce side: the user and permissions to prepare, which objects and fields Julian touches,
and the Salesforce behavior to plan for. Work through it before you connect. The steps inside Julian — connecting,
mapping an Agent Identifier, and building CRM workflows — are the same for every CRM and live in the [CRM
overview](/crm-integrations).

## How authentication works

Authorization is an OAuth login from the Julian app:

```text theme={null}
Integrations > Salesforce > Connect
```

You enter your Salesforce subdomain, then complete the standard Salesforce authorization screen. No managed package is
installed in your org. The one change to your org's configuration is that change notifications are turned on for the
objects Julian watches, which is recorded in your Setup Audit Trail.

<CardGroup cols={2}>
  <Card title="Credential handling" icon="shield-halved">
    Julian never stores your Salesforce credentials. Ampersand holds the OAuth tokens and refreshes them, and requests
    are made server-to-server.
  </Card>

  <Card title="Attribution" icon="user-check">
    Julian authorizes as a real Salesforce user. Every record Julian reads or writes is attributed to that user in
    Created By and Last Modified By.
  </Card>
</CardGroup>

## Which user to connect as

Any Salesforce user with the permissions below can authorize the connection, including your own account. We recommend
creating a **dedicated user** for Julian instead. It keeps attribution clean, caps everything Julian can reach at one
permission set you control, and lets you treat Julian like any other rep in routing and reporting. Connecting as a
person also ties the integration to their account, so it stops working if that account is deactivated.

Whichever user you use, it needs a Salesforce license that includes API access. An API-only **Salesforce Integration**
license is the cheapest option where your edition offers it; otherwise use a standard **Salesforce** license. A
**Salesforce Platform** license does not work.

## Required permissions

Grant these to the user you connect as, on their profile or on a permission set assigned to them. For a permission
set, go to **Setup → Permission Sets → New** and set **License** to match the user: **Salesforce API Integration** for
an API-only Integration user, or **None** for a standard Salesforce user. Enable the permissions below under **System
Permissions**, then save and assign the permission set to that user.

Four system permissions are required:

* **API Enabled** — lets Julian make API calls at all.
* **Use Any API Client**, or **Approve Uninstalled Connected Apps** — one of the two, whichever matches your org: the
  first if API Access Control is enabled, the second if it is not. Without one, Salesforce refuses the connection.
* **Modify Metadata Through Metadata API Functions** — lets Julian register the change notifications it watches for on
  Lead, Contact, and Account.
* **Customize Application** — Salesforce requires it for that same registration.

Julian watches your records by subscribing to changes rather than polling for them, which is what the last two are
for: a record reaches Julian within moments of the field changing, and it costs your org far fewer API calls than
repeated polling would. Salesforce enables **View Setup and Configuration**, **View Roles and Role Hierarchy**, and
**Manage Custom Permissions** automatically alongside those two, so you do not need to grant them yourself.

If the connection is still refused, the cause is usually elsewhere on the same user: **API Enabled** missing from
their profile, login IP ranges on the profile blocking the authorization, or a Salesforce Platform license instead of
a full Salesforce one. Retry in a fresh browser window after any change.

Then grant object access. Only the first row is needed by every setup — Julian can read records and place calls
without any write access at all. Grant the rest to match what you enable under **Push** and what your workflows
actually do, and nothing more.

| Object                                      | Access       | Needed for                                           |
| ------------------------------------------- | ------------ | ---------------------------------------------------- |
| **Lead**, **Contact**, **Account**          | Read         | Every setup — reading the records Julian calls       |
| **Lead**, **Contact**, **Account**          | Edit         | Writing outcomes and extracted values onto records   |
| **Task**                                    | Create, Edit | Logging calls, messages, and chat sessions           |
| **Files** (ContentVersion)                  | Create       | Attaching recordings and transcripts to those Tasks  |
| **EmailMessage**, **EmailMessageRelation**  | Create, Read | Logging emails to the CRM, if your workflows do that |
| **Opportunity**, **OpportunityContactRole** | Read         | Revenue reporting, if you enable it                  |

Field-level security matters as much as object access: every field you map in Julian must be visible to that user, and
writable if Julian writes to it. A field the user cannot see is simply absent.

<Note>
  What you grant is the ceiling on what Julian can reach — anything you leave out, it cannot see or touch. If a security
  review needs each permission justified line by line, your 11x contact can walk through it with you.
</Note>

## What Julian reads

Julian reads **Lead**, **Contact**, and **Account**. Campaign, Case, and existing Tasks are not read, and Opportunity
is read only if you enable revenue reporting.

Every record needs two mapped fields before Julian can act on it:

* **Agent Identifier** — the field that says which Julian agent the record belongs to.
* **Phone Number** — the number Julian dials.

Julian watches Lead, Contact, and Account for new records and for changes to the Agent Identifier field. **A record
only reaches Julian once that field holds a value**, so a record with the field empty is never sent, and clearing the
field stops new events for it. Everything else you want the agent to know — name, company, timezone, custom fields —
is optional and mapped the same way.

The Agent Identifier can be a text field, a picklist, or a field you already use for routing — Julian matches on the
value, not the field type.

<Note>
  If you gave Julian its own user, pointing the Agent Identifier at the record **Owner** and using that user's Id lets
  your existing round-robin assign work to Julian without a new field or a second routing flow.
</Note>

## What Julian writes

| What lands in Salesforce         | Object                     | Details                                                        |
| -------------------------------- | -------------------------- | -------------------------------------------------------------- |
| Call, message, and chat activity | **Task**                   | Subject, description, status, and a link to the call in Julian |
| Recording and transcript         | **Files** (ContentVersion) | Attached to the Task the activity created                      |
| Email activity                   | **EmailMessage**           | Plus a relation record linking it to the Contact or Lead       |
| Outcomes and extracted values    | Lead, Contact, or Account  | Whichever fields you map, including custom fields              |

Each activity is logged by a step in your workflow, so you choose which of them you want and what goes in them.
Meetings booked during a call are recorded in Julian and land on the host's calendar through your scheduling tool;
writing them into Salesforce as Events is not part of the standard integration, so raise it with your 11x contact if
you need it.

Call Tasks carry a Salesforce status that follows the call:

| Call result                                                                             | Task Status |
| --------------------------------------------------------------------------------------- | ----------- |
| Scheduled, Rescheduled                                                                  | Not Started |
| Completed, Voicemail, Not connected, Invalid phone number, Opted out, Cancelled, Failed | Completed   |

A Task is only closed in Salesforce at **Completed**, so a call that ends any of those ways closes its Task.

Anything the agent captures in conversation can be written to a field you nominate: an outcome such as "meeting
booked", a competitor name, a confirmed detail, the call status and duration, the attempt count, and a link back to
the call. Values that do not match a picklist option are safer written to a text field you process yourself.

## Salesforce behavior to plan for

<CardGroup cols={2}>
  <Card title="Converted leads" icon="arrows-turn-right">
    Salesforce rejects writes to a converted Lead. Julian follows the conversion and logs against the Contact or Account
    instead. A converted Lead with neither gets no activity.
  </Card>

  <Card title="Validation rules on Task" icon="triangle-exclamation">
    A rule that requires extra fields on call Tasks — a call type or result field, say — rejects Julian's write. Check
    your Task validation rules before going live.
  </Card>

  <Card title="Assignment rules" icon="shuffle">
    Assignment rules fire when Julian creates a record, the same as any other API create. Account for that if Julian
    creates Leads.
  </Card>

  <Card title="Duplicate rules" icon="clone">
    Julian runs its own duplicate check on phone and email before creating a record. Your Salesforce duplicate rules
    still apply on top and can block a create.
  </Card>

  <Card title="Record types" icon="tags">
    Julian does not set a Record Type on records it creates, so the connecting user needs a default record type on any
    object that requires one.
  </Card>

  <Card title="Enhanced Email" icon="envelope">
    Logging email as an EmailMessage needs Enhanced Email enabled. It is on by default in newer orgs; older orgs may
    need to turn it on.
  </Card>

  <Card title="Search results" icon="magnifying-glass">
    A Search CRM step returns up to 200 matching records. Filter narrowly enough that the record you want is in that
    set.
  </Card>

  <Card title="File storage" icon="hard-drive">
    Recordings attached as Files consume your org's file storage and are never cleaned up. At steady call volume this
    adds up — keep the call link and skip the recording upload if storage is tight.
  </Card>
</CardGroup>

## Verify the connection

1. In Julian, open **Integrations → Salesforce** and map the Agent Identifier and phone fields for the object you
   will use, then enable the objects Julian may write to.
2. Set the Agent Identifier field on one test record to the agent's value.
3. Confirm the call is scheduled for that record.
4. After the call, check the record in Salesforce for the logged Task and the fields you mapped.

<Warning>
  Julian works against the Salesforce org you authorize, and test runs execute real actions — they create Tasks, update
  records, and place calls. Use records you have set aside for testing.
</Warning>

With the connection verified, decide what the agent does with these records: see [Build your
workflows](/crm-integrations#build-your-workflows) for reading a record before a call and writing results back after
one.

## When a record does not arrive

Open **Integrations → Scheduling Request Logs** in Julian. Every record Salesforce sends is listed with what Julian
did with it, including the records it rejected and why — most often because the Agent Identifier did not match an
agent, the phone number was missing, or the record was treated as a duplicate.

For records that did reach a workflow, **Workflows → Run History** on the agent shows each run, the steps it took, and
what it wrote back.

If records stop arriving altogether, the connection itself may have been paused — for example after a credential
change in Salesforce. Reconnect from **Integrations → Salesforce**.
