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

# Salesforce troubleshooting

> Debug Salesforce connection, case creation, live messaging handoff, and agent reply sync issues.

Before debugging, have this ready:

* Admin access to both your Salesforce org and your [OpenCX dashboard](https://platform.open.cx/settings/integrations).
* A specific session ID (from [Inbox](https://platform.open.cx/inbox)) or Salesforce Case ID where the problem shows.
* The webhook URL shown in [Settings → Integrations](https://platform.open.cx/settings/integrations) → Salesforce (for email issues).

<Tip>
  Check connection status in [**Settings → Integrations**](https://platform.open.cx/settings/integrations) → Salesforce as your first step. Most issues are credential or configuration related.
</Tip>

## Email Cases

Jump to the symptom that matches what you're seeing.

### **"OAuth credentials won't save"**

<Tooltip tip="Usually caused by the External Client App not being active yet, or credentials copied with extra whitespace.">Likely cause</Tooltip>: External Client App still activating, or credentials copied incorrectly.

**Fix:** wait 2–10 minutes after creating the External Client App, then retry. Re-copy the Consumer Key and Consumer Secret without leading or trailing spaces. Confirm the Login URL is `https://login.salesforce.com` (production) or `https://test.salesforce.com` (sandbox).

### **"Connect to Salesforce fails"**

<Tooltip tip="The callback URL in the External Client App doesn't match what OpenCX sends, or the browser is blocking the popup.">Likely cause</Tooltip>: callback URL mismatch or popup blocked.

**Fix:** in Salesforce, open the External Client App and confirm the callback URL is exactly:

```
https://api.open.cx/backend/salesforce-case-management/oauth/callback
```

Allow popups for `platform.open.cx` in your browser.

### **"Handoff runs but no Case appears in Salesforce"**

<Tooltip tip="The Apex trigger isn't deployed, the Named Credential URL is wrong, or the webhook token has expired.">Likely cause</Tooltip>: Apex trigger not deployed or inactive, Named Credential misconfigured.

**Fix:**

1. In Salesforce **Setup → Apex Triggers**, confirm `CaseTrigger` is active.
2. In **Setup → Named Credentials**, confirm `OpenCX_Integration` points to the webhook URL from OpenCX (re-copy if it looks stale).
3. In **Setup → Apex Classes**, confirm `OpenSalesforceCaseManagement` is saved and active.

### **"AI replies show as sent in OpenCX but the contact never receives the email"**

<Tooltip tip="The OpenCxOutboundEmailSender trigger is missing from your Salesforce org, or Email Deliverability is set to 'System email only'.">Likely cause</Tooltip>: outbound delivery trigger not deployed, or org-wide email deliverability blocked.

A plain `EmailMessage` insert in Salesforce creates a record in the Case Feed but does not actually transmit the email — transmission requires `Messaging.sendEmail()` via the `OpenCxOutboundEmailSender` trigger. If the trigger is missing, the AI reply logs to the Case Feed (showing Status `Sent`) but never leaves Salesforce.

**Fix:**

1. In Salesforce **Setup → Apex Triggers**, confirm `OpenCxOutboundEmailSender` exists, is **Active**, and targets `EmailMessage`. If missing, deploy it per [Email Cases → Step 3, Trigger 5](/integrations/salesforce/email-cases#apex-triggers).
2. In **Setup → Email → Deliverability**, confirm **Access level** is `All email` (not `System email only` or `No access`).
3. Confirm the integration user's profile has the **Send Email** permission.
4. Re-send the AI reply from OpenCX. It should now land in the contact's inbox.

Run `SELECT Id, CreatedDate, FromAddress, ToAddress, Status FROM EmailMessage WHERE ParentId = '<caseId>' AND Incoming = false ORDER BY CreatedDate DESC` to confirm outbound records exist in Salesforce. If they do but the contact still doesn't receive the email, enable a **Debug Log** for the integration user (**Setup → Debug Logs → New** with the integration user as Traced Entity), re-send the reply from OpenCX, then open the resulting log and look for the `EmailMessage` insert transaction — confirm `OpenCxOutboundEmailSender` executed and didn't throw. If it didn't run, double-check in **Setup → Apex Triggers** that the trigger is still **Active**.

### **"Customer replies open a duplicate Case instead of threading into the original"**

<Tooltip tip="The outbound trigger isn't injecting Salesforce's Lightning-Threading token, so Email-to-Case can't match replies to the existing Case.">Likely cause</Tooltip>: `OpenCxOutboundEmailSender` is missing the call to `EmailMessages.getFormattedThreadingToken(em.ParentId)`, or an older version of the trigger is deployed.

**Fix:** update `OpenCxOutboundEmailSender` to the version documented at [Email Cases → Trigger 5](/integrations/salesforce/email-cases#apex-triggers). The current version appends the threading token to both the subject and the body, which is what Email-to-Case (Summer '22+) uses to attach customer replies to the same Case.

You can confirm by opening a recent outbound `EmailMessage` record on the Case Feed and checking its Subject/Body — you should see a `ref:!...:ref` token at the end. If the token isn't there, the trigger is stale.

### **"Customer replies never reach Salesforce at all"**

<Tooltip tip="Replies are going back to the integration user's personal Salesforce inbox because setReplyTo isn't configured, or the forwarding / Routing Address isn't registered with Email-to-Case.">Likely cause</Tooltip>: `REPLY_TO_ADDRESS` not set on the outbound trigger, or the reply-to address isn't registered as a verified Routing Address.

**Fix:**

1. In `OpenCxOutboundEmailSender`, confirm `REPLY_TO_ADDRESS` is set to your customer-facing forwarding address (e.g. `support@yourcompany.com`). Without `setReplyTo()`, replies go to the integration user's personal Salesforce inbox and never reach Email-to-Case.
2. In **Setup → Service → Email-to-Case → Routing Addresses**, confirm that same address is listed and its status is **Verified**. Until verified, Salesforce drops forwarded mail silently.
3. Confirm the forwarding itself works: send a plain email to your forwarding address, then check **Setup → Email Logs** — if no delivery record appears within 30 minutes, the forward is failing before it reaches Salesforce (usually SPF / DMARC). Publish an SPF record on your domain that includes `_spf.salesforce.com`, or switch to an SRS-aware forwarder.

### **"Hit `SINGLE_EMAIL_LIMIT_EXCEEDED` in the Debug Log"**

<Tooltip tip="Messaging.sendEmail has a hard per-org daily cap of 15/day on Developer/trial orgs and 5,000/day on Enterprise/Unlimited. Once exceeded, every subsequent send is rejected until midnight GMT.">Likely cause</Tooltip>: the org's external email cap for the GMT day is exhausted.

**Fix:**

1. Wait for midnight GMT — the counter resets automatically, no code change required.
2. If you're doing heavy iteration in a Developer / trial org (15/day cap), move testing to an Enterprise/Unlimited sandbox (5,000/day). The limit is a hardcoded edition characteristic — it cannot be raised on Dev Edition.
3. For high-volume production workloads that exceed 5,000/day, replace `Messaging.sendEmail` in `OpenCxOutboundEmailSender` with an HTTP callout to an external ESP (SendGrid / Postmark / Mailgun) via a Named Credential.

Note that `setTargetObjectId(contactId)` **does not** bypass this limit for external recipients — that optimisation only applies when the target is a Salesforce User record.

### **"Gmail forwarding stuck at `Unverified`"**

<Tooltip tip="Gmail sends a verification code to the Salesforce inbound address. Because Salesforce captures it as a Case, you need to pull the code out of Salesforce before pasting it back into Gmail.">Likely cause</Tooltip>: Gmail's forwarding handshake sent a verification code to Salesforce's long `@...case.salesforce.com` address; Salesforce received it as a new Case but you didn't retrieve the code to paste back into Gmail.

**Fix:**

1. In Gmail → **Settings → Forwarding and POP/IMAP** → click **Re-send email** next to the pending Salesforce address (sends a fresh code).

2. In Developer Console → Query Editor:

   ```sql theme={"dark"}
   SELECT Id, Subject, TextBody, CreatedDate
   FROM EmailMessage
   WHERE FromAddress = 'forwarding-noreply@google.com'
   ORDER BY CreatedDate DESC
   LIMIT 1
   ```

3. Open the newest row and copy the 9-digit confirmation code from the `TextBody`.

4. Paste the code into Gmail's verification input → **Verify**. Status should flip to `Confirmed` and forwarding is live.

The same pattern works for other mail providers (Outlook, FastMail, custom domains) — send a fresh verification, then pull the code from the newest `EmailMessage` in Salesforce.

### **"Rep replies don't reach the contact"**

<Tooltip tip="The Apex trigger isn't firing on case events, or the webhook URL is stale.">Likely cause</Tooltip>: webhook not firing or Named Credential URL outdated.

**Fix:** re-copy the webhook URL from [Settings → Integrations](https://platform.open.cx/settings/integrations) → Salesforce and update the Named Credential. Confirm the Apex trigger fires on Case `after insert`.

## Live Messaging

### **"MIAW settings won't save"**

<Tooltip tip="Instance URL is missing https://, or PEM keys are missing their header/footer lines.">Likely cause</Tooltip>: Instance URL format wrong or PEM encoding incomplete.

**Fix:** include `https://` in the Instance URL (e.g. `https://yourcompany.my.salesforce.com`). Ensure PEM keys include the `-----BEGIN PUBLIC KEY-----` and `-----BEGIN PRIVATE KEY-----` header and footer lines.

### **"Handoff fails with access token error"**

<Tooltip tip="The public/private key pair doesn't match, the Auth Key ID is wrong, or the key isn't registered in the Embedded Service Deployment.">Likely cause</Tooltip>: key mismatch or wrong Auth Key ID.

**Fix:** regenerate the RSA key pair, re-register the public key in your Salesforce Embedded Service Deployment's Auth Key settings, copy the new Auth Key ID, and update all six fields in the MIAW tab in OpenCX.

### **"Conversation created but no messages appear"**

<Tooltip tip="The ES Developer Name is wrong (it's case-sensitive) or Omni-Channel isn't configured for the Embedded Service Deployment.">Likely cause</Tooltip>: ES Developer Name mismatch or Omni-Channel not set up.

**Fix:** in Salesforce **Setup → Embedded Service Deployments**, copy the exact **API Name** (case-sensitive) and paste it into the ES Developer Name field in OpenCX. Confirm that Omni-Channel routing is configured for this deployment.

### **"Routing attributes missing in Salesforce"**

<Tooltip tip="Omni-Channel flow doesn't reference the attribute names OpenCX sends.">Likely cause</Tooltip>: Omni-Channel flow not reading the attributes.

**Fix:** in Salesforce **Setup → Omni-Channel Flows**, verify your flow references the attribute names (`OpencxSessionId`, `Chat_Consumer_Type`, `Origin`, `Priority`, `Chat_language`). Attributes are only useful if your flow reads them.

### Still stuck?

If none of the above resolves the issue, open a support request with:

* The session ID from [Inbox](https://platform.open.cx/inbox).
* The error message or unexpected behavior.
* Screenshots of your Salesforce setup (Named Credential, Apex Trigger status, or MIAW Embedded Service Deployment).

## Limits & timing

|                                    | Value                                          |
| ---------------------------------- | ---------------------------------------------- |
| **External Client App activation** | 2–10 minutes after creation                    |
| **Handoff retries**                | 3 attempts with increasing delays              |
| **Transcript length**              | Up to 4,000 characters per handoff message     |
| **Private key display**            | Redacted after first save — re-enter to change |

***

## Related Documentation

<CardGroup cols={2}>
  <Card title="Salesforce overview" icon="cloud" href="/integrations/salesforce/overview">
    Capabilities, supported channels, observability.
  </Card>

  <Card title="Email Cases" icon="envelope" href="/integrations/salesforce/email-cases">
    Re-verify OAuth, webhook, and Apex setup.
  </Card>

  <Card title="Live Messaging" icon="messages" href="/integrations/salesforce/live-messaging">
    Re-verify JWT credentials and routing attributes.
  </Card>

  <Card title="Handoff settings" icon="user-group" href="/handoff/introduction">
    Global handoff rules and office hours.
  </Card>
</CardGroup>
