Salesforce Integration

Salesforce Integration

Connect Salesforce Service Cloud to TR-AI using OAuth2 client credentials and a Connected App.

Note:Salesforce uses OAuth 2.0 client credentials flow — no user login or redirect URI required. TR-AI polls for new Cases every 30 seconds (configurable via SF_POLL_SECONDS environment variable). There is no webhook; TR-AI is the initiator.

Credentials required

FieldWhere to find it
Instance URLYour Salesforce org URL — e.g. https://myorg.my.salesforce.com
Client IDSetup → App Manager → Your Connected App → Consumer Key
Client SecretSetup → App Manager → Your Connected App → Consumer Secret
Sender Email (optional)Setup → Email → Org-Wide Email Addresses — a verified address for outbound replies

Step 1 — Create a Connected App

  1. 1
    Open App Manager
    Go to Setup → App Manager → New Connected App.
  2. 2
    Enable OAuth
    Check Enable OAuth Settings. Add scopes: api, refresh_token. Set Callback URL to any valid URL (e.g. https://ticketresolve.ai/oauth/callback) — it is not used for client credentials flow.
  3. 3
    Enable Client Credentials Flow
    After saving, go to Manage → Edit Policies. Under OAuth Policies, set Client Credentials Flow = Enabled. Assign a Run As user — this is the user whose permissions TR-AI inherits for all API calls.
  4. 4
    Copy credentials
    Go back to the Connected App and copy the Consumer Key (Client ID) and Consumer Secret (Client Secret).
Warning:The Run As user must have permission to read and update Cases, send emails, and query EmailMessage records. A System Administrator profile is simplest for testing; use a dedicated integration profile in production.

Step 2 — Set up an Org-Wide Email Address (recommended)

TR-AI sends replies via the emailSimple invocable action with senderType=OrgWideEmailAddress. This is the only email delivery mode that works reliably with client credentials OAuth — the Run As user's personal email (e.g. Gmail) will silently fail.

  1. 1
    Create the address
    Go to Setup → Email → Org-Wide Email Addresses → Add. Enter a display name and email address (e.g. support@yourcompany.com). Verify the address via the confirmation email.
  2. 2
    Enter it in TR-AI Dashboard
    In your TR-AI Dashboard, open the Salesforce card. Enter the verified address in the Sender Email field and click Save.
Tip:Without a Sender Email, TR-AI falls back to the EmailMessage sObject REST API (POST /services/data/v61.0/sobjects/EmailMessage) which accepts a free-form HTML body. This works but may have lower deliverability than a verified Org-Wide address.

Step 3 — Enter credentials in TR-AI

In your TR-AI Dashboard, open the Salesforce card. Enter your Instance URL, Client ID, and Client Secret. Optionally enter your Sender Email. Click Save. TR-AI will exchange credentials for a token and call GET /services/data/v61.0/limits to verify access.

How the Case Poller works

TR-AI polls your Salesforce org every 30 seconds (default) for Cases with Status='New'. For each new Case it runs the resolution engine and either:

  • Resolved: sends email via emailSimple → closes the Case (Status='Closed').
  • Triage: sends acknowledgement email → assigns Case to Triage queue if it exists, otherwise sets Status='Escalated'.

Recipient email resolution

TR-AI resolves the customer email address in this order:

  • SuppliedEmail — populated by Email-to-Case / Web-to-Case.
  • Latest inbound EmailMessage.FromAddress — from the most recent incoming email on the Case.
  • ContactEmail or Contact.Email — from the linked Contact record.

If no email address is found, TR-AI sets the Case to Status='Working' and adds an internal CaseComment explaining the failure.

Follow-up handling

TR-AI also polls for Cases in Working or Escalated status that have a new inbound EmailMessage in the last 10 minutes. These are treated as customer follow-up replies and processed with a timestamp-suffixed dedup key.

Deduplication

A Case is skipped only when a resolution_log row exists with replyPosted=true OR outcome IN ('triage', 'routed_to_agent'). Cases with outcome='incoming' or replyPosted=false are retried — they were interrupted mid-flight.

Token caching

Access tokens are cached in memory for 2 hours. On a 401 response, TR-AI force-refreshes the token once and retries the request automatically.

API version

TR-AI uses Salesforce REST API v61.0.