Salesforce integration failures with external systems

Salesforce integration failures with external systems

Source: Dev.to

Salesforce Integration Failures: How I Debugged and Fixed API Callout Issues in Production
Salesforce integrations look simple on paper.
Make a REST call. Send data. Get a response. In reality, Salesforce integrations fail in silent, unpredictable ways, especially in production: This post explains why Salesforce integrations fail, and how to fix them properly, step by step. The Core Problem
Salesforce integrations with external systems fail mainly because: Salesforce does not automatically “protect” your integration.
If you don’t handle failures explicitly, they go unnoticed. Step 1: Confirm the Integration Entry Point
First, identify where the integration is running: Most failures happen inside asynchronous Apex, not UI-triggered flows. Example (Queueable integration): System.enqueueJob(new SyncOrderJob(orderId)); If this job fails, the UI will never show an error. Step 2: Never Call External APIs Directly From Triggers
This is a very common Salesforce mistake.
Wrong approach Correct architecture
Trigger → Queueable → Callout Step 3: Use Named Credentials (Non-Negotiable)
Hardcoding endpoints or tokens will break in production.
Bad practice Correct approach (Named Credential) Go to Setup → Named Credentials Use it in Apex
req.setEndpoint('callout:Partner_API/orders'); Benefits: Step 4: Always Wrap Callouts in try–catch
This is the main reason Salesforce integrations fail silently. If it fails → job dies → no visibility. Step 5: Log Failures (Do Not Rely on Debug Logs)
Debug logs are temporary and unreliable in production. Create a custom Integration_Log__c object. Use it in catch blocks: Step 6: Handle Timeouts Explicitly
Salesforce has strict timeout limits.
req.setTimeout(10000); // 10 seconds If your external API is slow and you don’t set this: Step 7: Use Queueable Apex for Retries
Salesforce does not auto-retry failed callouts. Add retry logic manually. This alone fixes many “random” integration failures. Step 8: Check Remote Site Settings (Classic Issue)
If you are not using Named Credentials, your callout will fail silently. Go to:
Setup → Remote Site Settings
https://api.partner.com Missing this = guaranteed failure. Step 9: Test Callouts Properly (Mocking Required)
Salesforce will not allow real callouts in tests. Step 10: Monitor Async Jobs Regularly Go to:
Setup → Apex Jobs Key Takeaways
Salesforce integrations don’t fail because Salesforce is weak.
They fail because developers trust external systems too much. To make integrations production-safe: Once these practices are in place, Salesforce integrations become stable, observable, and predictable. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse CODE_BLOCK:
trigger OrderTrigger on Order__c (after insert) { HttpRequest req = new HttpRequest(); // Callout directly from trigger
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
trigger OrderTrigger on Order__c (after insert) { HttpRequest req = new HttpRequest(); // Callout directly from trigger
} CODE_BLOCK:
trigger OrderTrigger on Order__c (after insert) { HttpRequest req = new HttpRequest(); // Callout directly from trigger
} CODE_BLOCK:
trigger OrderTrigger on Order__c (after insert) { System.enqueueJob(new SyncOrderJob(Trigger.new));
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
trigger OrderTrigger on Order__c (after insert) { System.enqueueJob(new SyncOrderJob(Trigger.new));
} CODE_BLOCK:
trigger OrderTrigger on Order__c (after insert) { System.enqueueJob(new SyncOrderJob(Trigger.new));
} CODE_BLOCK:
req.setEndpoint('https://api.partner.com/v1/orders');
req.setHeader('Authorization', 'Bearer hardcoded_token'); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
req.setEndpoint('https://api.partner.com/v1/orders');
req.setHeader('Authorization', 'Bearer hardcoded_token'); CODE_BLOCK:
req.setEndpoint('https://api.partner.com/v1/orders');
req.setHeader('Authorization', 'Bearer hardcoded_token'); CODE_BLOCK:
HttpResponse res = http.send(req);
System.debug(res.getBody()); Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
HttpResponse res = http.send(req);
System.debug(res.getBody()); CODE_BLOCK:
HttpResponse res = http.send(req);
System.debug(res.getBody()); CODE_BLOCK:
try { Http http = new Http(); HttpResponse res = http.send(req); if (res.getStatusCode() != 200) { throw new CalloutException( 'API Error: ' + res.getStatus() + ' - ' + res.getBody() ); } } catch (Exception e) { System.debug('Integration failed: ' + e.getMessage());
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
try { Http http = new Http(); HttpResponse res = http.send(req); if (res.getStatusCode() != 200) { throw new CalloutException( 'API Error: ' + res.getStatus() + ' - ' + res.getBody() ); } } catch (Exception e) { System.debug('Integration failed: ' + e.getMessage());
} CODE_BLOCK:
try { Http http = new Http(); HttpResponse res = http.send(req); if (res.getStatusCode() != 200) { throw new CalloutException( 'API Error: ' + res.getStatus() + ' - ' + res.getBody() ); } } catch (Exception e) { System.debug('Integration failed: ' + e.getMessage());
} CODE_BLOCK:
public static void logError(String source, String message) { Integration_Log__c log = new Integration_Log__c( Source__c = source, Error_Message__c = message ); insert log;
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
public static void logError(String source, String message) { Integration_Log__c log = new Integration_Log__c( Source__c = source, Error_Message__c = message ); insert log;
} CODE_BLOCK:
public static void logError(String source, String message) { Integration_Log__c log = new Integration_Log__c( Source__c = source, Error_Message__c = message ); insert log;
} CODE_BLOCK:
catch (Exception e) { logError('Order Sync', e.getMessage());
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
catch (Exception e) { logError('Order Sync', e.getMessage());
} CODE_BLOCK:
catch (Exception e) { logError('Order Sync', e.getMessage());
} CODE_BLOCK:
if (retryCount < 3) { System.enqueueJob(new SyncOrderJob(orderId, retryCount + 1));
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
if (retryCount < 3) { System.enqueueJob(new SyncOrderJob(orderId, retryCount + 1));
} CODE_BLOCK:
if (retryCount < 3) { System.enqueueJob(new SyncOrderJob(orderId, retryCount + 1));
} CODE_BLOCK:
@isTest
private class OrderSyncTest { static testMethod void testCallout() { Test.setMock(HttpCalloutMock.class, new MockResponse()); Test.startTest(); System.enqueueJob(new SyncOrderJob(orderId)); Test.stopTest(); }
} Enter fullscreen mode Exit fullscreen mode CODE_BLOCK:
@isTest
private class OrderSyncTest { static testMethod void testCallout() { Test.setMock(HttpCalloutMock.class, new MockResponse()); Test.startTest(); System.enqueueJob(new SyncOrderJob(orderId)); Test.stopTest(); }
} CODE_BLOCK:
@isTest
private class OrderSyncTest { static testMethod void testCallout() { Test.setMock(HttpCalloutMock.class, new MockResponse()); Test.startTest(); System.enqueueJob(new SyncOrderJob(orderId)); Test.stopTest(); }
} - Data sync stops without warning
- Callouts fail intermittently
- Authentication suddenly breaks
- Jobs keep retrying but never succeed
I recently faced this issue in a live Salesforce org, and the root cause was not one thing—it was a combination of bad assumptions, missing error handling, and weak observability. - Callout errors are not logged properly
- Authentication tokens expire silently
- Timeout and retry logic is missing
- Errors happen inside async jobs (Batch, Queueable, Future)
- Developers assume APIs behave consistently - Trigger-based callout?
- Queueable Apex?
- Batch Apex?
- Scheduled job? - Callout exceptions
- Governor limit issues
- Unpredictable failures - Go to Setup → Named Credentials
- Configure: Base URL
Authentication (OAuth 2.0 / JWT / API Key)
- Authentication (OAuth 2.0 / JWT / API Key)
- Use it in Apex
req.setEndpoint('callout:Partner_API/orders'); Benefits: - Authentication (OAuth 2.0 / JWT / API Key) - Automatic token refresh
- Environment-safe
- More secure - Salesforce terminates the request
- No clear error is shown - Deployment blocked - Failed Queueables
- Aborted Batch jobs
- Long-running executions
Most integration failures show up here first. - Always use Named Credentials
- Never call APIs from triggers
- Log every failure
- Handle retries explicitly
- Treat async jobs as first-class systems