├── images ├── Consent.PNG ├── IntegratorKey.PNG └── DeveloperConsole.JPG ├── src ├── classes │ ├── DocuSignJWT.cls-meta.xml │ ├── DocuSignRESTUtility.cls-meta.xml │ ├── DocuSignJWT.cls │ └── DocuSignRESTUtility.cls ├── customMetadata │ ├── DocuSignRESTSettings.DSUserName.md │ ├── DocuSignRESTSettings.DSAccountID.md │ ├── DocuSignRESTSettings.RequestAuthDomain.md │ ├── DocuSignRESTSettings.RequestPrivateKey.md │ ├── DocuSignRESTSettings.RequestScope.md │ ├── DocuSignRESTSettings.CLMv2ApiEndpoint.md │ ├── DocuSignRESTSettings.RequestIntegratorKey.md │ ├── DocuSignRESTSettings.RequestAuthContentType.md │ ├── DocuSignRESTSettings.RequestAuthEndpoint.md │ └── DocuSignRESTSettings.RequestAuthBody.md ├── objects │ └── DocuSignRESTSettings__mdt.object ├── package.xml └── layouts │ └── DocuSignRESTSettings__mdt-DocuSignRESTSettings Layout.layout ├── .gitignore ├── LICENSE └── README.md /images/Consent.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docusign/code-examples-clm-apex/master/images/Consent.PNG -------------------------------------------------------------------------------- /images/IntegratorKey.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docusign/code-examples-clm-apex/master/images/IntegratorKey.PNG -------------------------------------------------------------------------------- /images/DeveloperConsole.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/docusign/code-examples-clm-apex/master/images/DeveloperConsole.JPG -------------------------------------------------------------------------------- /src/classes/DocuSignJWT.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 42.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/classes/DocuSignRESTUtility.cls-meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 42.0 4 | Active 5 | 6 | -------------------------------------------------------------------------------- /src/customMetadata/DocuSignRESTSettings.DSUserName.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | Value__c 7 | Replace with UserName 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/customMetadata/DocuSignRESTSettings.DSAccountID.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | Value__c 7 | Replace with DocuSign Account Id 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/customMetadata/DocuSignRESTSettings.RequestAuthDomain.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | Value__c 7 | account-d.docusign.com 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/customMetadata/DocuSignRESTSettings.RequestPrivateKey.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | Value__c 7 | Replace with Private Key 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/customMetadata/DocuSignRESTSettings.RequestScope.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | Value__c 7 | signature spring_read spring_write 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/customMetadata/DocuSignRESTSettings.CLMv2ApiEndpoint.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | Value__c 7 | https://apina11.springcm.com/v2/ 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/customMetadata/DocuSignRESTSettings.RequestIntegratorKey.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | Value__c 7 | Replace with Integrator Key 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/customMetadata/DocuSignRESTSettings.RequestAuthContentType.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | Value__c 7 | application/x-www-form-urlencoded 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/customMetadata/DocuSignRESTSettings.RequestAuthEndpoint.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | Value__c 7 | https://account-d.docusign.com/oauth/token 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/customMetadata/DocuSignRESTSettings.RequestAuthBody.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | Value__c 7 | grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion= 8 | 9 | 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # GitIgnore for Salesforce Projects 2 | # Project Settings and MetaData 3 | .project 4 | .settings/ 5 | .metadata 6 | build.properties 7 | config 8 | 9 | # Apex Log as optional 10 | apex-scripts/log 11 | 12 | # Eclipse specific 13 | salesforce.schema 14 | Referenced Packages 15 | bin/ 16 | tmp/ 17 | config/ 18 | *.tmp 19 | *.bak 20 | local.properties 21 | .settings 22 | .loadpath 23 | .classpath 24 | *.cache 25 | 26 | # Mavensmate 27 | *.sublime-project 28 | *.sublime-settings 29 | *.sublime-workspace 30 | mm.log 31 | 32 | # OSX-specific exclusions 33 | .[dD][sS]_[sS]tore -------------------------------------------------------------------------------- /src/objects/DocuSignRESTSettings__mdt.object: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Value__c 5 | false 6 | SubscriberControlled 7 | 8 | 131072 9 | LongTextArea 10 | 3 11 | 12 | 13 | DocuSignRESTSettings 14 | Public 15 | 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2018- DocuSign, Inc. (https://www.docusign.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /src/package.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | DocuSignRESTUtility 5 | DocuSignJWT 6 | ApexClass 7 | 8 | 9 | DocuSignRESTSettings__mdt.Value__c 10 | CustomField 11 | 12 | 13 | DocuSignRESTSettings.DSAccountID 14 | DocuSignRESTSettings.DSUserName 15 | DocuSignRESTSettings.RequestAuthBody 16 | DocuSignRESTSettings.RequestAuthContentType 17 | DocuSignRESTSettings.RequestAuthDomain 18 | DocuSignRESTSettings.RequestAuthEndpoint 19 | DocuSignRESTSettings.RequestIntegratorKey 20 | DocuSignRESTSettings.RequestPrivateKey 21 | DocuSignRESTSettings.RequestScope 22 | DocuSignRESTSettings.CLMv2ApiEndpoint 23 | CustomMetadata 24 | 25 | 26 | DocuSignRESTSettings__mdt 27 | CustomObject 28 | 29 | 30 | DocuSignRESTSettings__mdt-DocuSignRESTSettings Layout 31 | Layout 32 | 33 | 42.0 34 | 35 | -------------------------------------------------------------------------------- /src/layouts/DocuSignRESTSettings__mdt-DocuSignRESTSettings Layout.layout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | false 6 | true 7 | 8 | 9 | 10 | Required 11 | MasterLabel 12 | 13 | 14 | Required 15 | DeveloperName 16 | 17 | 18 | Edit 19 | Value__c 20 | 21 | 22 | 23 | 24 | Edit 25 | IsProtected 26 | 27 | 28 | Required 29 | NamespacePrefix 30 | 31 | 32 | 33 | 34 | 35 | false 36 | false 37 | true 38 | 39 | 40 | 41 | Readonly 42 | CreatedById 43 | 44 | 45 | 46 | 47 | Readonly 48 | LastModifiedById 49 | 50 | 51 | 52 | 53 | 54 | false 55 | false 56 | false 57 | 58 | 59 | 60 | false 61 | false 62 | false 63 | false 64 | false 65 | 66 | -------------------------------------------------------------------------------- /src/classes/DocuSignJWT.cls: -------------------------------------------------------------------------------- 1 | /* This class is responsible for constructing the JSON Web Token */ 2 | /* JSON Web Token will be sent to the DocuSign Authentication service for getting an access token which will be used in subsequent DocuSign API Calls */ 3 | /* Visit https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-jsonwebtoken for additional information on JSON Web token in DocuSign API */ 4 | 5 | 6 | public class DocuSignJWT { 7 | 8 | public String alg {get;set;} //RS256 for DocuSign REST integration 9 | public String iss {get;set;} // Integrator key 10 | public String sub {get;set;} // DSFProUserName from the user record 11 | public String aud {get;set;} // Authentication domain 12 | public String scope {get;set;} // signature scope 13 | public String privateKey {get;set;} //Private key 14 | public String exp {get;set;} 15 | public String iat {get;set;} 16 | public Map claims {get;set;} 17 | public Integer validFor {get;set;} 18 | public String cert {get;set;} 19 | public static final String HS256 = 'HS256'; 20 | public static final String RS256 = 'RS256'; 21 | public static final String NONE = 'none'; 22 | private static final String STRING_EMPTY = ''; 23 | 24 | 25 | //Constructor 26 | public DocuSignJWT(String alg,String sub,String iss, String privateKey,String scope,String aud) { 27 | this.alg = alg; 28 | this.sub = sub; 29 | this.iss = iss; 30 | this.privateKey = privateKey; 31 | this.scope = scope; 32 | this.validFor = 300; 33 | this.aud = aud; 34 | } 35 | 36 | //Method which returns the JSON Web Token 37 | public String issue() { 38 | String jwt = STRING_EMPTY; 39 | 40 | //Construct the JSON Web Token Header 41 | JSONGenerator header = JSON.createGenerator(false); 42 | header.writeStartObject(); 43 | header.writeStringField('alg', this.alg); 44 | header.writeStringField('typ','JWT'); // Set as JWT 45 | header.writeEndObject(); 46 | String encodedHeader = base64URLencode(Blob.valueOf(header.getAsString())); 47 | 48 | //Construct the JSON Body 49 | JSONGenerator body = JSON.createGenerator(false); 50 | body.writeStartObject(); 51 | body.writeStringField('iss', this.iss); 52 | body.writeStringField('sub', this.sub); 53 | body.writeStringField('aud', this.aud); 54 | Long rightNow = (dateTime.now().getTime()/1000)+1; 55 | body.writeNumberField('iat', rightNow); 56 | body.writeNumberField('exp', (rightNow + validFor)); 57 | body.writeStringField('scope', this.scope); 58 | if (claims != null) { 59 | for (String claim : claims.keySet()) { 60 | body.writeStringField(claim, claims.get(claim)); 61 | } 62 | } 63 | body.writeEndObject(); 64 | 65 | //JSON Web Token in this stage = encodedHeader + . + encodedBody 66 | jwt = encodedHeader + '.' + base64URLencode(Blob.valueOf(body.getAsString())); 67 | 68 | //Sign with Private key to create the signature 69 | if (this.alg == HS256 ) { 70 | Blob key = EncodingUtil.base64Decode(privateKey); 71 | Blob signature = Crypto.generateMac('hmacSHA256',Blob.valueof(jwt),key); 72 | jwt += '.' + base64URLencode(signature); 73 | } 74 | else if (this.alg == RS256 ) { 75 | Blob signature = null; 76 | if (cert != null) { 77 | signature = Crypto.signWithCertificate('rsa-sha256', Blob.valueOf(jwt), cert); 78 | } else { 79 | Blob privateKeyBlob = EncodingUtil.base64Decode(privateKey); 80 | //construct the signature 81 | signature = Crypto.sign('rsa-sha256', Blob.valueOf(jwt), privateKeyBlob); 82 | } 83 | jwt += '.' + base64URLencode(signature); 84 | } else if ( this.alg == NONE ) { 85 | jwt += '.'; 86 | } 87 | return jwt; 88 | 89 | } 90 | 91 | //Utility method for returning the base64URLEncoded string for the input string 92 | private String base64URLencode(Blob input){ 93 | String output = STRING_EMPTY; 94 | if (input != null) { 95 | output = encodingUtil.base64Encode(input); 96 | output = output.replace('+', '-'); 97 | output = output.replace('/', '_'); 98 | while ( output.endsWith('=')){ 99 | output = output.subString(0,output.length()-1); 100 | } 101 | } 102 | return output; 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # code-examples-clm-apex 2 | 3 | ## Introduction: 4 | This repository will aid end users in connecting to the CLM API from Salesforce using [Apex](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_intro_what_is_apex.htm) and The REST API. 5 | We will be using JWT Authentication for authenticating to DocuSign REST API's and then performing a folder search using the REST API. This recipe will serve as a building block for users to customize and apply their own strategies while interacting with CLM from Salesforce using Apex. 6 | 7 | ## Pre-requisites: 8 | - [Get a Salesforce Developer account](https://developer.salesforce.com/signup) 9 | 10 | - [Get a DocuSign Developer account](https://go.docusign.com/o/sandbox) 11 | 12 | ## Flow: 13 | - Set up your DocuSign Integration Key. 14 | - Find your DocuSign User ID and API Account ID. 15 | - Installing the Github source. 16 | - Set up Salesforce Custom Metadata. 17 | - Set up Salesforce Remote Sites. 18 | - Complete the Access Token Demo. 19 | 20 | ## Step-by-Step Walkthrough 21 | 22 | ### 1. Set up your DocuSign Integration key 23 | - Login to your DocuSign Developer Account and select **Admin**. 24 | - Under **Integrations**, select **API and Keys**. 25 | - Select **Add Integration Key** 26 | - Provide an **App Description** and select **Save** 27 | - Click on the newly created Integrator Key. From the window that appears, note down the **Integrator Key**. This will be a unique GUID which will be associated with your Integration Key. You'll need to add this value to Salesforce later. 28 | - Select **Add URI** and add 'https://localhost'. 29 | - Select **Add RSA Key Pair** and note down the Private Key. 30 | You'll need to add the Private Key to Salesforce later. **Do not copy the ----BEGIN RSA PRIVATE KEY---- and ----END RSA PRIVATE KEY---- lines**. 31 | Select OK. 32 | We have chosen to generate the RSA Key Pair since we will generating the JWT token to pass to the authentication key using the Private Key that we have noted down. This Private Key will be signed with the header and body of the request to complete the JWT token. Please see [JSON Web Token (JWT) Grant](https://developers.docusign.com/esign-rest-api/guides/authentication/oauth2-jsonwebtoken) for additional information on JWT and token construction. 33 | 34 | 35 | ![Integrator Key Screenshot](/images/IntegratorKey.PNG) 36 | 37 | #### Impersonating user for API calls 38 | Since our recipe will be using the Integration key to make CLM API calls, we must ensure that a DocuSign user provides consent to the Integrator Key performing actions on their behalf. In this case the DocuSign user will be our Developer account user. For service integrations, you can set up a service user and grant consent on this user's behalf. 39 | 40 | To complete this step open the following URI in a browser: 41 | 42 | `https://account-d.docusign.com/oauth/auth?response_type=code&scope=signature%20impersonation%20spring_read%20spring_write&client_id=YOUR_KEY&redirect_uri=https://localhost` 43 | 44 | Make sure that: 45 | - For the client_id, you substitute the correct Integration Key for YOUR_INTEGRATION_KEY. 46 | - The value for the redirect_uri parameter matches the redirect URI configured for the Integration Key in your DocuSign Developer Account. 47 | 48 | When you open the URL in your browser, a consent screen displays. Select **Accept**. 49 | 50 | ![Consent Screenshot](/images/Consent.PNG) 51 | 52 | After clicking Accept you will be redirected to the redirect URI you specified, indicating that consent was successfully granted. 53 | 54 | ### 2. Find your DocuSign User ID and API AccountID. 55 | - Log in to your DocuSign Developer Account and select **Admin**. 56 | - Under **'Integrations'**, select **API and Keys**. 57 | - Note down the **User ID** and **API Account ID**. You'll need to add these to your Salesforce Custom Metadata. 58 | 59 | ### 3. Install the GitHub Source: 60 | Deploy the files under the **src** folder to your Salesforce org. The src folder contains the a package.xml file which will help you to deploy the src. 61 | You can use [Workbench](https://workbench.developerforce.com/login.php) for installation: 62 | - Zip all the files such that folders and xml file present under the **src** folder are at the root of the zip file. 63 | - Log in to Workbench 64 | - Select **Migration -> Deploy** 65 | - Select the zip file created in the earlier step. Check the **Single Package** checkbox and click on **Next** 66 | - Select Deploy 67 | 68 | 69 | 70 | ### 4. Set up Salesforce Custom Metadata: 71 | - Once the source files have been deployed successfully to your Salesforce org, navigate to **Setup -> Custom metadata types**. 72 | - Click **Manage Records** under **DocuSignRESTSettings** 73 | - Replace the values in the settings with the values for your DocuSign instance: 74 | - DSAccount -> Your DocuSign API AccountID. 75 | - DSUserName -> Your DocuSign User ID. 76 | - RequestIntegratorKey -> Your Integration Key Id. 77 | - RequestPrivateKey -> Your Private Key. 78 | 79 | ### 5. Set up Salesforce Remote Sites: 80 | - Add 'https://account-d.docusign.com' as a Remote Site URL in your Salesforce instance. 81 | - Add the appropriate CLM REST API URL as a Remote Site URL in your Salesforce instance. You can find this in CLM Admin in the **Integrations** section of the **System Domains** page, or by consulting this chart: 82 | 83 | | | **North America** | **Europe** | 84 | |----------------|---------------------------------|---------------------------------| 85 | | **Test** | https://apiuatna11.springcm.com | https://apiuateu11.springcm.com | 86 | | **Production** | https://apina11.springcm.com | https://apieu11.springcm.com | 87 | 88 | 89 | ### 6. Complete the Access Token Demo: 90 | - Open the Developer Console 91 | - Press **CTRL + E** (open execute Anonymous code window) 92 | - Add the following line of code : 93 | `DocuSignRESTUtility.getAccessToken();` 94 | - Highlight the added line of code and press **Execute Highlighted** 95 | - Navigate to the generated log file and choose the *Debug Only* level to monitor the logs generated. 96 | - If the integration and setup are successfull you will notice a Status Code of 200 and the **ResponseAuthBody** parameter will also contain the `access_token` 97 | 98 | ![DeveloperConsole.JPG](/images/DeveloperConsole.JPG) 99 | 100 | ### 7. Search CLM for a folder using Apex: 101 | - Open the Developer Console 102 | - Press CTRL + E (open execute Anonymous code window) 103 | - Add the following line of code: 104 | `DocuSignRESTUtility.searchForFolder('SEARCH_QUERY');` 105 | - Highlight the added line of code and press **Execute Highlighted** 106 | 107 | This example should search your CLM instance for folders matching the search query. 108 | 109 | ## License 110 | 111 | The DocuSign CLM Apex code examples are licensed under the following [License](LICENSE). 112 | -------------------------------------------------------------------------------- /src/classes/DocuSignRESTUtility.cls: -------------------------------------------------------------------------------- 1 | /* This class is responsible for searching for folders by making REST Callouts to DocuSign CLM */ 2 | /* You can extend the searchForFolder method by invoking it from triggers / scheduled apex / batch jobs */ 3 | /* You can also create invocable actions by referencing the searchForFolder method and use it in Process Builders */ 4 | 5 | public class DocuSignRESTUtility { 6 | 7 | //Get Rest Configuration Setings from Custom Metadata provided as a part of the installation source 8 | private static Map settingsMap { 9 | //Getter Method 10 | get { 11 | //populate only if settingsMap is null 12 | if (settingsMap == null) { 13 | settingsMap = new Map(); 14 | //Query the Custom Metadata and add it to the Map 15 | //Query against Custom Metadata does not count against the SOQL query Limit 16 | for (DocuSignRESTSettings__mdt setting : [Select DeveloperName,MasterLabel, Value__c from DocuSignRESTSettings__mdt]) { 17 | settingsMap.put(setting.MasterLabel, setting); 18 | } 19 | } 20 | return settingsMap; 21 | } 22 | //Blank Setter Method 23 | set { 24 | } 25 | } 26 | 27 | //This method will call the DocuSignJWT class to obtain an access token from DocuSign 28 | public static String getAccessToken() { 29 | String access_token = null; 30 | 31 | //Instantiate a request object 32 | HttpRequest req = new HttpRequest(); 33 | //set the request METHOD 34 | req.setMethod('POST'); 35 | 36 | //set the request endpoint 37 | String authendpoint = settingsMap.get('RequestAuthEndpoint').Value__c; 38 | System.Debug(LoggingLevel.INFO, '**RequestAuthEndpoint' + authendpoint); 39 | req.setEndPoint(authendpoint); 40 | 41 | //set the request headers 42 | //1. Content -type 43 | String authRequestContentType = settingsMap.get('RequestAuthContentType').Value__c; 44 | System.Debug(LoggingLevel.INFO, '**authRequestContentType ' + authRequestContentType); 45 | req.setHeader('Content-type', authRequestContentType); 46 | 47 | //2. Host 48 | String authRequestDomain = settingsMap.get('RequestAuthDomain').Value__c; 49 | System.Debug(LoggingLevel.INFO, '**authRequestDomain ' + authRequestDomain); 50 | req.setHeader('Host', authRequestDomain); 51 | 52 | //Body of the request 53 | String alg = 'RS256'; 54 | String iss = settingsMap.get('RequestIntegratorKey').Value__c; 55 | String pkey = settingsMap.get('RequestPrivateKey').Value__c; 56 | String scope = settingsMap.get('RequestScope').Value__c; 57 | DocuSignJWT jwtObject = new DocuSignJWT(alg, settingsMap.get('DSUserName').Value__c, iss, pkey, scope, authRequestDomain); 58 | 59 | //Set the request body 60 | String requestBody = settingsMap.get('RequestAuthBody').Value__c + jwtObject .issue(); 61 | System.Debug(LoggingLevel.INFO, '**RequestAuthBody' + requestBody); 62 | req.setBody(requestBody); 63 | 64 | //call the service 65 | Http http = new Http(); 66 | HTTPResponse res = http.send(req); 67 | 68 | System.Debug(LoggingLevel.INFO, '**ResponseAuthBody' + res.getbody()); 69 | System.Debug(LoggingLevel.INFO, '**ResponseAuth' + res); 70 | 71 | //Obtain the access token from the Response 72 | if (res.getStatusCode() == 200) { 73 | System.JSONParser parser = System.JSON.createParser(res.getBody()); 74 | while (parser.nextToken() != null) { 75 | if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'access_token')) { 76 | parser.nextToken(); 77 | access_token = parser.getText(); 78 | break; 79 | } 80 | } 81 | } 82 | 83 | return access_token; 84 | 85 | } 86 | 87 | @future(callout=true) 88 | public static void searchForFolder(string query) { 89 | //Get the access token 90 | String accessToken = getAccessToken(); 91 | System.Debug(LoggingLevel.INFO, '***accessToken ' + accessToken); 92 | 93 | //Call CLM API if a non-empty access token is returned 94 | if (!String.isEmpty(accessToken)) { 95 | //instantiate an Http instance 96 | Http httpProtocol = new Http(); 97 | 98 | //instantiate an HttpRequest instance 99 | HttpRequest request = new HttpRequest(); 100 | 101 | //Set the request parameters 102 | // Request endpoint for folder search call 103 | String endpoint = settingsMap.get('CLMv2ApiEndpoint').Value__c + settingsMap.get('DSAccountID').Value__c + '/folders/search?search=' + query; 104 | System.Debug(LoggingLevel.INFO, '***endpoint ' + endpoint); 105 | request.setEndPoint(endpoint); 106 | 107 | //set the POST method 108 | request.setMethod('POST'); 109 | 110 | //set Authentication Header 111 | request.setHeader('grant_type', 'Bearer'); 112 | request.setHeader('Authorization', 'Bearer ' + accessToken); 113 | 114 | //set Accept Header 115 | request.setHeader('Accept', 'application/json'); 116 | 117 | //set Content Type Header 118 | request.setHeader('Content-type', 'application/json'); 119 | 120 | //set Empty Body - Check out https://developers.docusign.com/docs/clm-api/reference/Objects/Folders/Search/ for more details if required 121 | request.setBody(''); 122 | 123 | //Make the request and capture the response 124 | HttpResponse response = httpProtocol.send(request); 125 | System.Debug(LoggingLevel.INFO, '***response.getBody() ' + response.getBody()); 126 | System.debug(LoggingLevel.INFO, '***response.getStatus() ' + response.getStatus()); 127 | 128 | //Parse the response 129 | String responseStatus = response.getStatus(); 130 | if (responseStatus.equals('Created')) { 131 | DocuSignRESTUtility.FolderSearchResponse responseObject = new DocuSignRESTUtility.FolderSearchResponse(); 132 | responseObject = (DocuSignRESTUtility.FolderSearchResponse)System.JSON.deserialize(response.getBody(), DocuSignRESTUtility.FolderSearchResponse.class); 133 | System.Debug(LoggingLevel.INFO, '***responseObject ' + responseObject); 134 | } 135 | } 136 | } 137 | 138 | //wrapper class for Folder Search Response 139 | public class FolderSearchResponse 140 | { 141 | public FolderItem[] Items { get; set; } 142 | public String Href { get; set; } 143 | public long Offset { get; set; } 144 | public String First { get; set; } 145 | public String Last { get; set; } 146 | public long Total { get; set; } 147 | } 148 | 149 | public class FolderItem 150 | { 151 | public String Name { get; set; } 152 | public DateTime CreatedDate { get; set; } 153 | public String CreatedBy { get; set; } 154 | public DateTime UpdatedDate { get; set; } 155 | public String UpdatedBy { get; set; } 156 | public String Description { get; set; } 157 | public Documents ParentFolder { get; set; } 158 | public String BrowseDocumentsUrl { get; set; } 159 | public AccessLevel AccessLevel { get; set; } 160 | public Documents Documents { get; set; } 161 | public Documents Folders { get; set; } 162 | public Documents ShareLinks { get; set; } 163 | public String CreateDocumentHref { get; set; } 164 | public String Href { get; set; } 165 | } 166 | 167 | public class AccessLevel 168 | { 169 | public boolean See { get; set; } 170 | public boolean Read { get; set; } 171 | public boolean Write { get; set; } 172 | public boolean Move { get; set; } 173 | public boolean Create { get; set; } 174 | public boolean SetAccess { get; set; } 175 | } 176 | 177 | public class Documents 178 | { 179 | public String Href { get; set; } 180 | } 181 | 182 | } 183 | --------------------------------------------------------------------------------