{ Analytica Model Salesforce_REST_library, encoding="UTF-8" } SoftwareVersion 7.2.1 LinkLibrary Salesforce_REST_library Title: Salesforce REST library Description: REST + JSON client for Salesforce API v67.0. Supports OAuth client credentials or legacy SOAP login authentication, paginated SOQL queries, record retrieval, SOSL search, and sObject metadata. Do not store credentials in this library. Author: Assista~ Lumina Decision Systems Date: Thu, Aug 13, 2026 3:39 PM NodeSize: 80,24 NodeInfo: 1,,,,,,,0,,,,,,0 DiagState: 2,152,34,1440,571,17,10 WindState: 2,98,82,720,350 FontStyle: Arial,15 FileInfo: 0,LinkLibrary Salesforce_REST_library,2,2,0,0,Salesforce REST library.ana {!60500|NamespaceDefaultScope: Public} {!60500|NamespaceImports: Internals} {!70000|Struct ClientCredentialsAuth(login_url : Text atom ; client_id : Text atom ; client_secret : Text atom )} {!70000|Title: Client credentials authentication} {!70000|Description: Obtains a Salesforce OAuth 2.0 access token using the client credentials flow. Calling ClientCredentialsAuth(login_url, client_id, client_secret) returns an instance containing access_token, instance_url, HTTP response status, and raw response.} {!70000|Definition: Local form :=~ ['grant_type': 'client_credentials',~ 'client_id': client_id,~ 'client_secret': client_secret];~ Local (response, status_code, status_text) := IgnoreWarnings(~ ReadFromUrl(~ login_url & '/services/oauth2/token',~ method: 'POST',~ formValues:form,~ httpHeaders:~ 'Content-Type: application/x-www-form-urlencoded'~ & Chr(13) & 'Accept: application/json',~ connectTimeoutMs: 30000,~ sendTimeoutMs: 30000,~ receiveTimeoutMs: 30000,~ expandSecrets:true~ )~ );~ Self -> status_code := status_code;~ Self -> status_text := status_text;~ Self -> raw_response := response;~ If status_code <> 200 Then~ Error(~ 'Salesforce OAuth client-credentials login failed (HTTP '~ & NumberToText(status_code) & '): ' & response~ )~ Else (~ Local token := ParseJSON(response);~ Self -> access_token := token -> access_token;~ Self -> instance_url := token -> instance_url;~ Self~ )} {!70000|NodeLocation: 192,152,2} {!70000|NodeSize: 112,32} {!70000|NodeInfo: 1,,,,,,,0,,,,,,0} {!70000|DiagState: 2,0,1,1264,476,17,10} {!70000|WindState: 2,281,31,822,578} {!70000|NamespaceDefaultScope: Private} {!70104|Att_GUID: ac5c2a86-f3b9-4a5f-83ea-3501e368b282} Close ClientCredentialsAuth {!70000|Struct Salesforce(auth : atom )} {!70000|Title: Salesforce connection} {!70000|Description: Creates a Salesforce REST connection from an authentication Struct, including ClientCredentialsAuth or SoapLoginAuth. Calling Salesforce(auth) exposes the authenticated instance URL, bearer token, REST base URL, and fixed API version 67.0 for subsequent REST query functions.} {!70000|Definition: Self -> api_version := '67.0';~ Self -> instance_url := auth -> instance_url;~ Self -> access_token := auth -> access_token;~ Self -> rest_base_url :=~ auth -> instance_url & '/services/data/v' & Self -> api_version;~ Self} {!70000|NodeLocation: 448,152,2} {!70000|NodeSize: 112,32} {!70000|NodeInfo: 1,,,,,,,0,,,,,,0} {!70000|DiagState: 2,0,1,1264,476,17,10} {!70000|WindState: 2,667,19,720,344} {!70000|NamespaceDefaultScope: Private} Close Salesforce {!70000|Struct SoapLoginAuth(login_url : Text atom ; username : Text atom ; password : Text atom ; security_token : Text atom )} {!70000|Title: SOAP login authentication (legacy)} {!70000|Description: Obtains a Salesforce session ID using the legacy SOAP Partner API login() call (v51.0). The session ID can be used as a REST bearer token. Deprecated authentication path: migrate to ClientCredentialsAuth before Salesforce retires SOAP login on 2027-06-01. (i.e., This method of authentication will stop working after 1-Jun-2027)} {!70000|Definition: { Salesforce Partner SOAP login endpoint remains at v51.0. }~ Local safe_username :=~ TextReplace(~ TextReplace(~ TextReplace(username, '&', '&', all: true),~ '<', '<', all: true~ ),~ '>', '>', all: true~ );~ Local login_password := password & security_token;~ Local safe_password :=~ TextReplace(~ TextReplace(~ TextReplace(login_password, '&', '&', all: true),~ '<', '<', all: true~ ),~ '>', '>', all: true~ );~ Local envelope :=~ ''~ & ''~ & ''~ & '' & safe_username & ''~ & '' & safe_password & ''~ & '';~ Local (response, status_code, status_text) := IgnoreWarnings(~ ReadFromUrl(~ login_url & '/services/Soap/u/51.0',~ method: 'POST',~ httpContent: envelope,~ httpHeaders:~ 'Content-Type: text/xml; charset=UTF-8'~ & Chr(13) & 'SOAPAction: login',~ connectTimeoutMs: 30000,~ sendTimeoutMs: 30000,~ receiveTimeoutMs: 30000~ )~ );~ Self -> status_code := status_code;~ Self -> status_text := status_text;~ Self -> raw_response := response;~ If status_code <> 200 Then~ Error(~ 'Salesforce SOAP login failed (HTTP '~ & NumberToText(status_code) & '): ' & response~ )~ Else (~ Local fault := FindInText(~ '<[^>]*faultstring[^>]*>([^<]*)]*faultstring>',~ response, re: 1, return: 'S', subpattern: 1~ );~ If Not IsNull(fault) Then~ Error('Salesforce SOAP login failed: ' & fault)~ Else (~ Local session_id := FindInText(~ '<[^>]*sessionId[^>]*>([^<]+)]*sessionId>',~ response, re: 1, return: 'S', subpattern: 1~ );~ Local server_url := FindInText(~ '<[^>]*serverUrl[^>]*>([^<]+)]*serverUrl>',~ response, re: 1, return: 'S', subpattern: 1~ );~ Local instance_url := FindInText(~ '^(https://[^/]+)', server_url,~ re: 1, return: 'S', subpattern: 1~ );~ If IsNull(session_id) Or IsNull(instance_url) Then~ Error('Salesforce SOAP login returned no session ID or instance URL')~ Else (~ Self -> access_token := session_id;~ Self -> instance_url := instance_url;~ Self -> api_version := '51.0';~ Self~ )~ )~ )} {!70000|NodeLocation: 448,240,2} {!70000|NodeSize: 112,32} {!70000|NodeInfo: 1,,,,,,,0,,,,,,0} {!70000|WindState: 2,98,82,720,350} {!70000|NamespaceDefaultScope: Private} Close SoapLoginAuth Module Internals Title: Internals Description: Private implementation objects for the Salesforce REST library. This module is in scope for library functions and intentionally out of namespace scope for library users. Author: Lonnie Chrisman, Ph.D.~ Lumina Decision Systems Date: Thu, Aug 13, 2026 3:39 PM NodeLocation: 1056,624,2 NodeSize: 112,24 DiagState: 2,0,1,1264,476,17,10 {!60500|NamespaceDefaultScope: Public} {!60500|NamespaceScope: Private} {!70000|Struct SfResponse(body : Text atom ; status_code : Number atom ; status_text : Text atom ; headers : Text atom ; content_type : Text atom ; json : atom )} {!70000|Title: Salesforce HTTP response} {!70000|Description: Internal normalized HTTP response used by the Salesforce REST library.} {!70000|Definition: Self} {!70000|NodeLocation: 160,72,1} {!70000|NodeSize: 64,32} {!70000|NodeInfo: 1,,,,,,,0,,,,,,0} {!70000|NamespaceDefaultScope: Private} Close SfResponse {!70000|Struct SfQueryResult(records ; ~ total_size : Number atom ; ~ pages : Number atom ; ~ done : atom ; ~ next_records_url : atom ; ~ raw_response : atom )} {!70000|Title: Salesforce query result} {!70000|Description: Internal query result packet. Records is a list of parsed Salesforce record Structs.} {!70000|Definition: Self} {!70000|NodeLocation: 352,64,1} {!70000|NodeSize: 64,24} {!70000|NodeInfo: 1,,,,,,,0,,,,,,0} {!70000|DiagState: 2,0,1,1264,476,17,10} {!70000|WindState: 2,98,82,720,350} {!70000|NamespaceDefaultScope: Private} Close SfQueryResult Function SfValidateName(name : Text atom ; allow_path : atom := false ) Title: Validate Salesforce API name Description: Internal guard for Salesforce object and field API names used while assembling SOQL. Definition: Local pattern := If allow_path Then~ '^[A-Za-z_][A-Za-z0-9_]*(\.[A-Za-z_][A-Za-z0-9_]*)*$'~ Else~ '^[A-Za-z_][A-Za-z0-9_]*$';~ If IsNull(FindInText(pattern, name, re: 1, return: 'S')) Then~ Error('Invalid Salesforce API name: ' & name)~ Else~ name NodeLocation: 544,72,1 NodeSize: 64,32 NodeInfo: 1,,,,,,,0,,,,,,0 Function SfRequest(sf : atom ; method : Text atom ; path : Text atom ; query_string : Text atom := '' ; json_body : Text atom := '' ) Title: Salesforce REST request Description: Internal authenticated JSON request helper. Normalizes the response and raises on non-2xx HTTP status. Definition: Local absolute := Not IsNull(~ FindInText('^https?://', path, re: 1, return: 'S')~ );~ Local url :=~ (If absolute Then path Else sf -> instance_url & path)~ & query_string;~ Local auth_headers :=~ 'Authorization: Bearer ' & sf -> access_token~ & Chr(13) & 'Accept: application/json'~ & Chr(13) & 'Content-Type: application/json';~ Local (body, status_code, status_text, headers, content_type) :=~ If TextUpperCase(method) = 'GET' Then~ IgnoreWarnings(~ ReadFromUrl(~ url,~ method: method,~ httpHeaders: auth_headers,~ connectTimeoutMs: 30000,~ sendTimeoutMs: 30000,~ receiveTimeoutMs: 30000~ )~ )~ Else~ IgnoreWarnings(~ ReadFromUrl(~ url,~ method: method,~ httpContent: json_body,~ httpHeaders: auth_headers,~ connectTimeoutMs: 30000,~ sendTimeoutMs: 30000,~ receiveTimeoutMs: 30000~ )~ );~ If status_code = 401 Then~ Error(~ 'Salesforce rejected the access token (HTTP 401). '~ & 'Recalculate the authentication and Salesforce connection, then retry. '~ & SelectText(body, 1, 400)~ )~ Else If status_code < 200 Or status_code >= 300 Then~ Error(~ method & ' ' & url & ' failed (HTTP '~ & NumberToText(status_code) & '): '~ & SelectText(body, 1, 400)~ )~ Else~ SfResponse(~ body,~ status_code,~ status_text,~ headers,~ content_type,~ ParseJSON(body)~ ) NodeLocation: 736,64,1 NodeSize: 64,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,98,82,930,654 Function SfQueryPage(sf : atom ; soql_or_next_url : Text atom ; include_deleted : atom := false ) Title: Salesforce query page Description: Internal helper that retrieves one SOQL query page or one nextRecordsUrl page. Definition: Local is_next := Not IsNull(~ FindInText('^(https?://|/)', soql_or_next_url, re: 1, return: 'S')~ );~ Local response := If is_next Then~ SfRequest(sf, 'GET', soql_or_next_url)~ Else~ SfRequest(~ sf,~ 'GET',~ sf -> rest_base_url~ & If include_deleted Then '/queryAll' Else '/query',~ '?q=' & TextCharacterEncode('URL', soql_or_next_url)~ );~ Local body := response -> json;~ SfQueryResult(~ `->`(body, 'records', defVal: []),~ `->`(body, 'totalSize', defVal: 0),~ 1,~ `->`(body, 'done', defVal: true),~ `->`(body, 'nextRecordsUrl', defVal: Null),~ response~ ) NodeLocation: 928,64,1 NodeSize: 64,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,151,56,849,555 Close Internals Function SalesforceSoqlQuote(value : Text atom ) Title: Quote a SOQL text value Description: Escapes a text value for use as a SOQL string literal and surrounds it with single quotes. Use this for values, not object or field API names. Definition: Local escaped := TextReplace(value, '\', '\\', all: true);~ escaped := TextReplace(escaped, '''', '\' & '''', all: true);~ escaped := TextReplace(escaped, '"', '\"', all: true);~ escaped := TextReplace(escaped, Chr(10), '\n', all: true);~ escaped := TextReplace(escaped, Chr(13), '\r', all: true);~ escaped := TextReplace(escaped, Chr(9), '\t', all: true);~ escaped := TextReplace(escaped, Chr(8), '\b', all: true);~ escaped := TextReplace(escaped, Chr(12), '\f', all: true);~ '''' & escaped & '''' NodeLocation: 800,144,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,1351,126,720,350 Function SalesforceQuery(sf : atom ; soql : Text atom ; include_deleted : atom := false ; max_pages : Number atom := 100 ) Title: Query Salesforce Description: Executes SOQL through the Salesforce REST API, follows pagination, and returns a query-result Struct containing records, total_size, pages, done, next_records_url, and raw_response. Definition: Local page := SfQueryPage(sf, soql, include_deleted);~ Local records := page -> records;~ Local pages := 1;~ Local total_size := page -> total_size;~ While Not page -> done And pages < max_pages Do (~ page := SfQueryPage(sf, page -> next_records_url, include_deleted);~ records := Concat(records, page -> records);~ pages := pages + 1~ );~ If Not page -> done Then~ Error(~ 'Salesforce query exceeded max_pages='~ & NumberToText(max_pages)~ & '; refine the SOQL or increase max_pages.'~ )~ Else~ SfQueryResult(~ records,~ total_size,~ pages,~ page -> done,~ page -> next_records_url,~ page -> raw_response~ ) NodeLocation: 1056,144,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,943,109,720,604 Function SalesforceQueryFirst(sf : atom ; soql : Text atom ) Title: Query first Salesforce record Description: Executes SOQL and returns the first matching record Struct, or Null when no record matches. Definition: Local page := SfQueryPage(sf, soql, false);~ If page -> total_size = 0 Then Null Else page -> records[@=1] NodeLocation: 800,208,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,98,82,720,350 Function SalesforceCount(sf : atom ; soql : Text atom ; include_deleted : atom := false ) Title: Count Salesforce query records Description: Returns the totalSize reported by Salesforce for a SOQL query without requiring callers to inspect the record list. Definition: SfQueryPage(sf, soql, include_deleted) -> total_size NodeLocation: 1056,208,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,98,82,720,350 Function SalesforceDescribe(sf : atom ; sobject : Text atom ) Title: Describe Salesforce object Description: Returns Salesforce metadata for an sObject, including fields, relationships, picklists, and permissions. Definition: Local object_name := SfValidateName(sobject);~ SfRequest(~ sf,~ 'GET',~ sf -> rest_base_url & '/sobjects/' & object_name & '/describe'~ ) -> json NodeLocation: 800,480,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,534,24,720,350 Function SalesforceObjects(sf : atom ) Title: List Salesforce objects Description: Returns the list of sObject summary Structs available to the authenticated Salesforce user. Definition: SfRequest(~ sf,~ 'GET',~ sf -> rest_base_url & '/sobjects'~ ) -> json -> sobjects NodeLocation: 1056,480,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,98,82,720,350 Function SalesforceFields(sf : atom ; sobject : Text atom ) Title: List Salesforce fields Description: Returns the field metadata Structs from SalesforceDescribe for the specified sObject. Definition: SalesforceDescribe(sf, sobject) -> fields NodeLocation: 800,552,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,492,121,720,350 Function SalesforceGetRecord(sf : atom ; sobject : Text atom ; record_id : Text atom ; fields : Text atom ) Title: Get Salesforce record Description: Retrieves one Salesforce record by sObject API name and record ID. Fields is a comma-separated list of field API names. Definition: Local object_name := SfValidateName(sobject);~ If IsNull(~ FindInText('^[A-Za-z0-9]{15,18}$', record_id, re: 1, return: 'S')~ ) Then~ Error('Invalid Salesforce record ID: ' & record_id);~ Local field_list := SplitText(fields, ',');~ Local n := 1;~ While n <= Size(field_list) Do (~ SfValidateName(TextTrim(field_list[@=n]), true);~ n := n + 1~ );~ SfRequest(~ sf,~ 'GET',~ sf -> rest_base_url & '/sobjects/' & object_name & '/' & record_id,~ '?fields=' & TextCharacterEncode('URL', fields)~ ) -> json NodeLocation: 192,480,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,775,126,713,564 Function SalesforceGetRecords(sf : atom ; sobject : Text atom ; record_ids : List ; fields : Text atom ) Title: Get Salesforce records Description: Retrieves multiple records by Salesforce IDs using SOQL. record_ids is a list; fields is a comma-separated list of field API names. Definition: Local object_name := SfValidateName(sobject);~ Local field_list := SplitText(fields, ',');~ Local n := 1;~ While n <= Size(field_list) Do (~ SfValidateName(TextTrim(field_list[@=n]), true);~ n := n + 1~ );~ Local quoted_ids := SalesforceSoqlQuote(record_ids);~ Local soql :=~ 'SELECT ' & fields~ & ' FROM ' & object_name~ & ' WHERE Id IN ('~ & JoinText(quoted_ids, separator: ',') & ')';~ SalesforceQuery(sf, soql) -> records NodeLocation: 448,480,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 Function SalesforceSearch(sf : atom ; sosl : Text atom ) Title: Search Salesforce Description: Executes a Salesforce Object Search Language (SOSL) expression and returns searchRecords. Definition: SfRequest(~ sf,~ 'GET',~ sf -> rest_base_url & '/search',~ '?q=' & TextCharacterEncode('URL', sosl)~ ) -> json -> searchRecords NodeLocation: 192,552,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,1495,121,720,350 Function SalesforceSelect(sf : atom ; ~ sobject : Text atom ; ~ fields : Text atom ; ~ where : named Text atom := '' ; ~ order_by : named Text atom := '' ; ~ row_limit : named Number atom := 0 ~ ) Title: Select Salesforce records Description: Builds and executes a common SOQL SELECT. fields is comma-separated; where_clause and order_by are optional SOQL fragments without their keywords. Definition: Local object_name := SfValidateName(sobject);~ Local field_list := SplitText(fields, ',');~ Local n := 1;~ While n <= Size(field_list) Do (~ SfValidateName(TextTrim(field_list[@=n]), true);~ n := n + 1~ );~ Local soql := 'SELECT ' & fields & ' FROM ' & object_name;~ If TextLength(TextTrim(where)) > 0 Then~ soql := soql & ' WHERE ' & where;~ If TextLength(TextTrim(order_by)) > 0 Then~ soql := soql & ' ORDER BY ' & order_by;~ If row_limit > 0 Then~ soql := soql & ' LIMIT ' & NumberToText(Floor(row_limit));~ SalesforceQuery(sf, soql) NodeLocation: 448,552,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,98,82,946,654 Function SalesforceField(record : atom ; field_path : Text atom ; default_value : atom := Null ) Title: Get Salesforce record field Description: Extracts a dynamically named member from a Salesforce record Struct. A dotted field path such as Account.Name traverses relationship Structs; default_value is returned when a member is absent. Definition: Local parts := SplitText(field_path, '.');~ Local value := record;~ Local n := 1;~ While n <= Size(parts) And Not IsNull(value) Do (~ If TypeOf(value, shallow: true) <> 'Struct' Then~ value := default_value~ Else~ value := `->`(value, parts[@=n], defVal: default_value);~ n := n + 1~ );~ value NodeLocation: 1056,552,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,98,82,720,350 Function SalesforceQueryPage(sf : atom ; soql_or_next_url : Text atom ; include_deleted : atom := false ) Title: Query one Salesforce page Description: Retrieves one SOQL query page. Pass a SOQL expression for the first page or a next_records_url from a prior result for the next page. Definition: SfQueryPage(sf, soql_or_next_url, include_deleted) NodeLocation: 928,272,2 NodeSize: 112,24 NodeInfo: 1,,,,,,,0,,,,,,0 WindState: 2,98,82,720,350 Text Auth_connection_cluster Title: Authentication & connection Description: Token acquisition and the reusable Salesforce connection. NodeLocation: 320,200,1 NodeSize: 280,144 NodeInfo: 1,,,,1,1,1,0,,,,,,0 NodeColor: 0xffe0ffff NodeFont: ,13 {!50400|NodeBorderColor: 0xff4682b4} Text Querying_cluster Title: SOQL queries Description: Build, execute, page, and summarize Salesforce queries. NodeLocation: 928,200,1 NodeSize: 280,144 NodeInfo: 1,,,,1,1,1,0,,,,,,0 NodeColor: 0xffe6e6fa NodeFont: ,13 {!50400|NodeBorderColor: 0xff9370db} Text Records_search_cluster Title: Records & search Description: Retrieve records and use higher-level selection or search helpers. NodeLocation: 320,536,1 NodeSize: 280,144 NodeInfo: 1,,,,1,1,1,0,,,,,,0 NodeColor: 0xfff0fff0 NodeFont: ,13 {!50400|NodeBorderColor: 0xff2e8b57} Text Metadata_helpers_cluster Title: Metadata & implementation Description: Discover schema details, access fields, and inspect internal support code. NodeLocation: 928,536,1 NodeSize: 280,144 NodeInfo: 1,,,,1,1,1,0,,,,,,0 NodeColor: 0xffffffe0 NodeFont: ,13 {!50400|NodeBorderColor: 0xffdaa520} Constant Salesforce_library_version Title: Salesforce library version Description: A version number for this library, numeric, major + minor/100. Definition: 1.01 NodeLocation: 784,632,1 NodeSize: 64,24 WindState: 2,98,82,720,350 {!70000|Struct SFLogin( )} {!70000|Title: Salesforce user login authentication} {!70000|Description: Interactive Salesforce OAuth 2.0 authorization-code login for desktop Analytica. Call SFLoginAuth(login_url, client_id, redirect_port), e.g. with https://login.salesforce.com and the port registered in the Salesforce app (the user's test uses 18756). The browser signs in as the current user; Salesforce UserInfo supplies the REST instance URL. Returns a Salesforce connection Struct (access_token, instance_url, rest_base_url, api_version) ready for SalesforceQuery and the other library functions. Do not store client secrets here. Requests api and refresh_token scopes, but does not implement token refresh; a new login may be needed after expiration.} {!70000|Definition: Local url := 'https://login.salesforce.com/services/oauth2';~ Local access_token := OAuth2Authorize(~ { Note: The external app client ID is public }~ client_id: '3MVG99OxTyEMCQ3jmWw2TGaAnrB6ZnOIzs75mhyb59XMbU5NMz7klWDZKPw45NBiFq4.XjYgm1kH9bdNhUVc5',~ auth_url: f"{url}/authorize",~ token_url: f"{url}/token",~ scope: 'api refresh_token',~ redirect_port: 18756~ );~ Local (response, status_code, status_text) := IgnoreWarnings(~ ReadFromUrl(~ f"{url}/userinfo",~ method: 'GET',~ httpHeaders: 'Authorization: Bearer ' & access_token~ & Chr(13) & 'Accept: application/json',~ connectTimeoutMs: 30000,~ sendTimeoutMs: 30000,~ receiveTimeoutMs: 30000~ )~ );~ If status_code <> 200 Then~ Error(~ 'Salesforce user information request failed (HTTP '~ & NumberToText(status_code) & ').'~ )~ Else (~ Local user_info := ParseJSON(response);~ Local rest_url := user_info -> urls -> rest;~ Local instance_url := FindInText(~ '^(https://[^/]+)', rest_url,~ re: 1, return: 'S', subpattern: 1~ );~ If IsNull(instance_url) Then~ Error('Salesforce user information returned no REST instance URL')~ Else (~ Self -> access_token := access_token;~ Self -> instance_url := instance_url;~ Self -> api_version := '67.0';~ Self -> rest_base_url :=~ instance_url & '/services/data/v' & Self -> api_version;~ Self~ )~ )} {!70000|NodeLocation: 192,240,2} {!70000|NodeSize: 112,32} {!70000|NodeInfo: 1,,,,,,,0,,,,,,0} {!70000|DiagState: 2,0,1,1264,476,17,10} {!70000|WindState: 2,134,130,1052,529} {!70104|Att_GUID: 571eeaab-6b45-409d-bbf2-62fae51680f9} Close SFLogin Close Salesforce_REST_library