Passer au contenu principal

Intégration Salesforce avec Flow

Mouna Hilal avatar
Écrit par Mouna Hilal
Mis à jour il y a plus d’une semaine

*Important, vous devez avec les accès Admin et avoir la license Enterprise, Performance ou Unlimited pour avoir accès à l'outil Flow.

Voici les 3 étapes :

1. Il faut autoriser l'URL du API d'InputKit dans Salesforce

1.1. Setup

1.2. Remote Site Settings

1.3. Ajouter l'URL d'InputKit dans les Remote Site Settings

Clique sur New Remote Site

Mettre ce URL : https://api.inputkit.io

2. Créer la class Apex "InputKit Send Sequence"

Il faut créer la classe Apex pour pouvoir l'utiliser dans le Flow

2.1 Apex Classes

2.2 New

Copier coller ce code :

public with sharing class InputKitSendSequence {
@InvocableMethod(label='Send InputKit Sequence' description='Sends a sequence via InputKit API and returns the response')
public static List<ResponseWrapper> sendSequence(List<Request> requests) {
List<ResponseWrapper> results = new List<ResponseWrapper>();
Http http = new Http();

for (Request req : requests) {
String endpoint = 'https://api.inputkit.io/v3/send/' + EncodingUtil.urlEncode(req.sequenceId, 'UTF-8');
HttpRequest httpReq = new HttpRequest();
httpReq.setEndpoint(endpoint);
httpReq.setMethod('POST');
httpReq.setHeader('Content-Type', 'application/json');
httpReq.setHeader('inputkit_api_key', req.apiKey);

// Build body
Map<String, Object> body = new Map<String, Object>{
'location_id' => req.locationId,
'creation_source' => req.creationSource
};
if (req.email != null) body.put('email', req.email);
if (req.phone != null) body.put('phone', req.phone);
if (req.firstName != null) body.put('first_name', req.firstName);
if (req.lastName != null) body.put('last_name', req.lastName);
if (req.fullName != null) body.put('full_name', req.fullName);
if (req.honorific != null) body.put('honorific', req.honorific);
if (req.locale != null) body.put('locale', req.locale);
if (req.sendingModes != null) body.put('sending_modes', req.sendingModes);
if (req.timeToSend != null) body.put('time_to_send', req.timeToSend);

httpReq.setBody(JSON.serialize(body));

ResponseWrapper wrap = new ResponseWrapper();
try {
HttpResponse res = http.send(httpReq);
wrap.statusCode = res.getStatusCode();
wrap.responseBody = res.getBody();
wrap.success = (res.getStatusCode() >= 200 && res.getStatusCode() < 300);
if (!wrap.success) {
// Force Flow to see an error
wrap.errorMessage = 'Non-2xx response: ' + res.getStatusCode() + ' / ' + res.getBody();
}
} catch (Exception e) {
wrap.success = false;
wrap.errorMessage = 'Callout exception: ' + e.getMessage();
}
results.add(wrap);
}

return results;
}

public class Request {
@InvocableVariable(label='Sequence Id' required=true) public String sequenceId;
@InvocableVariable(label='API Key' required=true) public String apiKey;
@InvocableVariable(label='Location Id' required=true) public Integer locationId;
@InvocableVariable(label='Creation Source' required=true) public String creationSource;
@InvocableVariable(label='Email') public String email;
@InvocableVariable(label='Phone') public String phone;
@InvocableVariable(label='First Name') public String firstName;
@InvocableVariable(label='Last Name') public String lastName;
@InvocableVariable(label='Full Name') public String fullName;
@InvocableVariable(label='Honorific') public String honorific;
@InvocableVariable(label='Locale') public String locale;
@InvocableVariable(label='Sending Modes') public String sendingModes;
@InvocableVariable(label='Time To Send (UTC)') public String timeToSend;
}

public class ResponseWrapper {
@InvocableVariable(label='Success') public Boolean success;
@InvocableVariable(label='Status Code') public Integer statusCode;
@InvocableVariable(label='Body') public String responseBody;
@InvocableVariable(label='Error Msg') public String errorMessage;
}
}

2.3 Classe test (si votre Salesforce oblige une classe de test)

Créer une 2e classe Apex et coller ce code :

@IsTest
private class InputKitSendSequenceTest {
// Mock to simulate HTTP callouts
private class MockHttpResponseGenerator implements HttpCalloutMock {
private Integer statusCode;
private String responseBody;

public MockHttpResponseGenerator(Integer statusCode, String responseBody) {
this.statusCode = statusCode;
this.responseBody = responseBody;
}

public HTTPResponse respond(HTTPRequest req) {
HttpResponse res = new HttpResponse();
res.setHeader('Content-Type', 'application/json');
res.setBody(this.responseBody);
res.setStatusCode(this.statusCode);
return res;
}
}

@IsTest
static void testSendSequenceSuccess() {
// Prepare mock for a 201 Created response
Test.setMock(HttpCalloutMock.class,
new MockHttpResponseGenerator(201, '{"message":"Sequence sent"}'));

// Build the request
InputKitSendSequence.Request req = new InputKitSendSequence.Request();
req.sequenceId = 'seq123';
req.apiKey = 'test_api_key';
req.locationId = 42;
req.creationSource = 'TEST';
req.email = '[email protected]';
req.firstName = 'Foo';
req.lastName = 'Bar';

Test.startTest();
List<InputKitSendSequence.ResponseWrapper> results =
InputKitSendSequence.sendSequence(
new List<InputKitSendSequence.Request>{ req }
);
Test.stopTest();

// Assertions
System.assert(results.size() == 1, 'One result expected');
InputKitSendSequence.ResponseWrapper wrap = results[0];
System.assert(wrap.success == true, 'Callout should be marked as success');
System.assert(wrap.statusCode == 201, 'HTTP status must be 201');
System.assert(wrap.responseBody.contains('Sequence sent'),
'Response body should contain our JSON message');
System.assert(wrap.errorMessage == null,
'No error message on success');
}

@IsTest
static void testSendSequenceFailure() {
// Prepare mock for a 400 Bad Request response
Test.setMock(HttpCalloutMock.class,
new MockHttpResponseGenerator(400, '{"error":"Invalid payload"}'));

// Build the minimal request
InputKitSendSequence.Request req = new InputKitSendSequence.Request();
req.sequenceId = 'badSeq';
req.apiKey = 'invalid_key';
req.locationId = 0;
req.creationSource = 'TEST_FAIL';

Test.startTest();
List<InputKitSendSequence.ResponseWrapper> results =
InputKitSendSequence.sendSequence(
new List<InputKitSendSequence.Request>{ req }
);
Test.stopTest();

// Assertions
System.assert(results.size() == 1, 'One result expected');
InputKitSendSequence.ResponseWrapper wrap = results[0];
System.assert(wrap.success == false, 'Callout should be marked as failure');
System.assert(wrap.statusCode == 400, 'HTTP status must be 400');
System.assert(wrap.responseBody.contains('Invalid payload'),
'Response body should contain the error message');
System.assert(wrap.errorMessage.startsWith('Non-2xx response'),
'errorMessage should describe status and body');
}
}

3. Utiliser le service SendSequence dans le Flow

3.1 Flows --> New Flow

Sur le Trigger, il faut activer le "Add Async Path"

Et ajouter les actions en dessous du "Run Asynchronously"

3.2 Ajouter un Action à l'endroit de votre choix

3.3 Send InputKit Sequence (Apex)

3.4 Remplir les champs

  • API KEY : Votre clé API de votre compte InputKit, dans vos Paramètres > Intégrations

  • Creation Source : Salesforce

  • Location Id : Le ID du bureau, trouvé dans votre page Bureaux

  • Sequence Id, trouvé dans votre page Sequences

La valeur du champ peut venir de l'object qui a trigger le Flow, ou de n'importe quelle autre étape précédente dans le Flow

Exemple, le Last Name du client vient du Triggering Case.

Et je vais sur le Contact associé au Case pour prendre le Last Name.

Avez-vous trouvé la réponse à votre question ?