Skip to main content
Before debugging, have this ready:
  • Admin access to both your Salesforce org and your OpenCX dashboard.
  • A specific session ID (from Inbox) or Salesforce Case ID where the problem shows.
  • The webhook URL shown in Settings → Integrations → Salesforce (for email issues).
Check connection status in Settings → Integrations → Salesforce as your first step. Most issues are credential or configuration related.

Email Cases

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

”OAuth credentials won’t save”

: Connected App still activating, or credentials copied incorrectly. Fix: wait 2–10 minutes after creating the Connected 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”

: callback URL mismatch or popup blocked. Fix: in Salesforce, open the Connected App and confirm the callback URL is exactly:
Allow popups for platform.open.cx in your browser.

”OAUTH_APPROVAL_ERROR_GENERIC after logging in to Salesforce”

Salesforce shows “We can’t authorize you because of an OAuth error … OAUTH_APPROVAL_ERROR_GENERIC : An unexpected error has occurred during authentication.” : a scope mismatch between what OpenCX requests and what the app grants. The common case: the app is an External Client App (which cannot grant Full access (full)) while the OpenCX workspace still requests full — the historical default. Fix:
  1. Using an External Client App? Ask OpenCX to switch your workspace to the least-privilege scope set (api id refresh_token offline_access), and select exactly the three matching checkboxes on the app — see Create an External Client App.
  2. Using a classic Connected App? Make sure every scope OpenCX requests is selected on the app (Full access + Perform requests at any time for the default configuration).
  3. If you recreated the app, paste the new Consumer Key and Secret into OpenCX and save — retrying with the old app’s saved credentials keeps failing the same way. Wait 2–10 minutes after app creation, then Save and Connect again.

”error=invalid_client_id when redirected to Salesforce”

: the app was created moments ago, or the Consumer Key was copied incorrectly. Fix: wait 2–10 minutes and retry. If it persists, re-copy the Consumer Key (no whitespace) and confirm the Login URL points at the org that owns the app — for a sandbox use https://test.salesforce.com, or use your org’s My Domain URL directly.

”OAUTH_AUTHORIZATION_BLOCKED — Cross-org OAuth flows are not supported for this external client app”

: you authorized into a different Salesforce org than the one that owns the app. A generic Login URL (https://test.salesforce.com or https://login.salesforce.com) sends you to whichever org your credentials resolve to, which need not be the app’s org. Fix:
  1. Set the Login URL to the My Domain URL of the org that owns the app — for example https://yourorg--sandboxname.sandbox.my.salesforce.com. This pins the flow to one org and is the single most common fix.
  2. If it still fails, the app genuinely lives elsewhere. An External Client App cannot be reused across orgs unless it is packaged and distributed, so create the app inside the org you are connecting.
  3. Leaving the Login URL blank silently defaults to production — a frequent cause when you meant to connect a sandbox.

”Connection works, then stops a few hours later”

Cases stop creating sessions and rep replies stop syncing. OpenCX logs Unable to refresh session due to: expired access/refresh token, and reconnecting fixes it only until the next token expiry. : the app’s refresh token policy expires the refresh token. Fix: in the app’s OAuth policies, set the Refresh Token Policy to Refresh token is valid until revoked, then reconnect once. Also confirm the app grants Perform requests at any time (refresh_token, offline_access) — without it no usable refresh token is ever issued.

”Case comments and replies are authored by the wrong Salesforce user”

: the integration is connected as the wrong user. Fix: log out of Salesforce (or use a private window), sign in as the user you want, then Save and Connect again. Full steps and the requirements that user must meet are in Changing the integration user.

”Case created in Salesforce but no session appears in OpenCX”

: the @future webhook callout is failing inside Salesforce. Fix:
  1. Setup → Apex Jobs — find the failed future jobs from your test; the error column names the exact cause.
  2. Setup → Named Credentials — the Name must exactly match the callout: reference in the Apex class (OpenCX_Integration by default), and the URL must be the base Webhook URL from the OpenCX dashboard: everything up to and including /webhook, with the token segment removed.
  3. The token must reach us as a header. Confirm the Apex class sets x-opencx-token (or Authorization: Bearer) and that the value it reads is populated — an empty protected Custom Setting yields a blank header and the webhook is rejected with Missing webhook token. A token left in the URL path still works, but it leaks into debug logs and Apex Jobs entries; move it to the header.
  4. Passing Apex tests do not prove this path — tests mock the callout (HttpCalloutMock), so a broken Named Credential still shows green tests.

”Emails to my support address never create a Case”

: the forward from your support mailbox to the long ...case.salesforce.com address isn’t confirmed, or the Routing Address isn’t verified. Fix: in Setup → Email-to-Case → Routing Addresses, the address must show Verified. Then confirm the mailbox forward itself (e.g. Gmail’s forwarding confirmation — the code lands in Salesforce as an EmailMessage; see Email Cases Step 3). Emails sent directly to the long Email Services Address bypass forwarding — if those create Cases but your support address doesn’t, the forward is the broken link.

”Handoff runs but no Case appears in Salesforce”

: 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 base webhook URL from OpenCX — no token segment (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”

: 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.
  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”

: 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. 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”

: 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. [email protected]). 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”

: 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

: 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:
  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”

: webhook not firing or Named Credential URL outdated. Fix: re-copy the webhook URL from Settings → Integrations → Salesforce and update the Named Credential. Confirm the Apex trigger fires on Case after insert.

Live Messaging

”MIAW settings won’t save”

: 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”

: 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 under In-App Chat (MIAW) in OpenCX.

”Conversation created but no messages appear”

: 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”

: 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.
  • The error message or unexpected behavior.
  • Screenshots of your Salesforce setup (Named Credential, Apex Trigger status, or MIAW Embedded Service Deployment).

Limits & timing


Salesforce overview

Capabilities, supported channels, observability.

Email Cases

Re-verify OAuth, webhook, and Apex setup.

Live Messaging

Re-verify JWT credentials and routing attributes.

Handoff settings

Global handoff rules and office hours.