RBA Cash Rate: 4.35% · 1AUD = 0.67 USD · Inflation: 4.1%  
Leading Digital Marketing Experts</strong | 1300 235 433 | Aggregation Enquires Welcome | Book Appointment
Example Interest Rates: Home Loan Variable: 5.69% (5.89%*) • Home Loan Fixed: 5.39% (6.59%*) • Fixed: 5.39% (6.59%*) • Variable: 5.69% (5.89%*) • Investment IO: 5.69% (6.48%*) • Investment PI: 5.39% (6.59%*)

Authentication and Basic Queries With the SalesTrekker GraphQL API

Authentication and Basic Queries With the SalesTrekker GraphQL API

On the morning of Sunday the 10th this year I sent SalesTrekker an email after experiencing issues with their RESTful API. The support response came shortly after advising that the API has been completely depreciated in favour of the newer GraphQL service. There was no notification, no transition, no warning, and no mention of the imminent change in the email reply I'd received a few days earlier regarding another issue. With the weeks of works we'd put into building a full and complete library for integration into mortgage broker businesses one would be forgiven if we were upset (our ST integration included everything from basic queries all the way up to full-featured online applications). However, the truth is that despite SalesTrekker's occasional (and costly) shortcomings it's still the leading platform for Mortgage Broker growth. We'll work with anything and everything in the market but it's ST that we see consistently delivering better broker and consumer outcomes.

The GraphQL query and manipulation language - the API query language now used by SalesTrekker - was first used by Facebook in 2012 before it was released to the general market in September of 2015. If you're interested in learning more about the advantages (and disadvantages) you should check out GraphQL.org for detailed documentation.

There are some clear advantages in using SalesTrekker's V2 GraphQL API over the now retired RESTful service, such as the ability to return large amounts of necessary data via a single query when multiple slow queries were previously necessary (there's an example of this below). While we would have liked a depreciation timeline on Version 1 of ST's API, it might have been advantageous that we were forced into a new product.

This article builds upon documentation made available on the ST website and will show you how to authenticate a user in the ST system, and how to make simple requests. Quoting from ST's developer website, "... due to the strongly typed, enforceable, self explanatory nature of GraphQL schema, as well as the opportunity to test API directly within the playground, there is no other backing documentation to the API". Given that there's no documentation, and since migrating over to GraphQL does introduce various challenges, we figured that we'd share some basic articles for DIY brokers that are simply looking to see how the API works (when documentation otherwise wouldn't be available). We've also scheduled a number of posts that provide some basic functionality made available via the ST webhooks. Nothing we're providing on this page is suitable for a production environment.

Authentication

You can authenticate yourself with SalesTrekker via one of two means:

  1. Via your account API Key (provides full administrative privileges).
  2. Via your Username and Password. Privileges are assigned to the logged-in user.

If you plan on authenticating via your account API Key you'll have to retrieve it by navigating your way to your Settings menu (top right), and then to the API menu in the left menu. Hidden for privacy reasons, you're required to first click 'Reveal API Key'.

SalesTrekker API Menu

SalesTrekker API Menu. Source: SalesTrekker.

Reveal SalesTrekker API Key

Reveal SalesTrekker API Key. Source: SalesTrekker.

Unlike most traditional REST APIs your API key cannot be used to directly access SalesTrekker resources. Instead, you'll have to use your API Key to validate against the system and return a JavaScript Web Token (JWT).

Note: If you refresh or change your API key without consideration to attached third-party systems (including ours), those connected systems will cease to work.

Before we have a look at a function that'll actually query ST data, it's worth mentioning that you can interact and play directly with the API via the GraphQL Playground . It's an essential tool for visually building your queries without using the Schema directly. Shown below is the query necessary to validate using your API Key.

SalesTrekker API Playground

SalesTrekker API Playground.

The JWT token is shown in the right-hand panel.

The query used was as follows:

1
<?php 
2
mutation{
3
  authenticate(apiKey:"df8d1bxxxxxxxxxxxxxxxdf873901dxxxxxf5457") {
4
    token
5
  }
6
}

If we were to authenticate with a username and password we would use the following:

1
<?php 
2
mutation{
3
  authenticate(email:"you@youremail.com.au" password:"xxxxxxxxxxxxxxxxxxxxxx") {
4
    token
5
  }
6
}

Of course, you'll want to retrieve and renew your token programmatically; the following example is a non-production example of what might be used.

1
<?php 
2
/*
3
 Retrieve SalesTrekker JWT
4
 https://www.beliefmedia.com.au/salestrekker-api
5
*/
6
 
7
function beliefmedia_salestrekker_graphql_token($apikey = '') {
8
 
9
  if ($apikey == '') return false;
10
 
11
  /* Authentication with API Key, formatted JSON */
12
  $data = '{"query":"mutation{\n  authenticate(apiKey:\"' . $apikey . '\") {\n    token\n  }\n}\n"}';
13
 
14
  /* Curl Request */
15
  $ch = curl_init();
16
 
17
  /* Get fields */
18
  curl_setopt($ch, CURLOPT_URL, 'https://dev.salestrekker.com/graphql');
19
  curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
20
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
21
  curl_setopt($ch, CURLOPT_TIMEOUT, 30);
22
  curl_setopt($ch, CURLOPT_POST, true);
23
  curl_setopt($ch, CURLOPT_ENCODING, '');
24
  curl_setopt($ch, CURLOPT_HTTPHEADER, array(
25
    'User-Agent: BeliefMedia/1.0',
26
    'Accept-Encoding: gzip, deflate, br',
27
    'Content-Type: application/json',
28
    'Origin: https://beliefmedia.net',
29
    'Connection: Keep-Alive',
30
    'Content-Length:' . strlen($data)
31
  ));
32
 
33
  /* Execute */
34
  $result = curl_exec($ch);
35
 
36
  /* GraphQL will usually return an error property - 200 normally returned */
37
  $response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
38
  if ($response_code != '200') {
39
 /* Do something if CURL screws the pooch */
40
 file_put_contents(time() . '-auth-' . $response_code . '.txt', curl_error($ch));
41
 return false;
42
  }
43
 
44
  /* Close CURL */
45
  curl_close($ch);
46
 
47
  $return = json_decode($result, true);
48
 
49
 return $return;
50
}

Usage is as follows:

1
$token_jwt = beliefmedia_salestrekker_graphql_token('dfxx1bfxxxxxxxxxx4333df87xxxxxxxxxxf5457');

Alter the header origin to your own secure URL. Requests cannot be made from a non-secure domain.

Once we've retrieved the token there are a couple of steps necessary to retrieve information from the JWT string.

The JavaScript Web Token

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA. Basically, what this means is that we can use a secret key to validate the data returned to us.

The JWT takes on three parts: the Header, Payload, and Signature. Each part is separated by a period sign. While far from best practice we can return each part by exploding the JWT string as shown below.

1
<?php 
2
/*
3
 Unwrap SalesTrekker JWT
4
 https://www.beliefmedia.com.au/salestrekker-api
5
*/
6
 
7
function beliefmedia_salestrekker_jwt($token) {
8
 
9
  $pieces = explode('.', $token);
10
 
11
    $payload['0'] = json_decode(base64_decode($pieces['0']));
12
    $payload['1'] = json_decode(base64_decode($pieces['1']));
13
    $payload['2'] = $pieces['2'];
14
 
15
    /* The token requires validation in the production environment */
16
 
17
 return $payload;
18
}

The JWT parts will be returned as follows:

1
Array
2
(
3
    [0] => stdClass Object
4
        (
5
            [alg] => HS256
6
            [typ] => JWT
7
        )
8
 
9
    [1] => stdClass Object
10
        (
11
            [id] => 802xxxx1-fxx8-4xx0-axxc-6bxxxxxxx2fe
12
            [idCurrentOrganization] => ddxxx2f9-9xx3-4xx8-8xxe-13xxxxxxx8f6
13
            [iat] => 1554900835
14
            [exp] => 1556110435
15
        )
16
 
17
    [2] => u7WpxxxxxxxxxxxxxxZRiPq-anFGyO_7UxxxxxxxnYI
18
)

The Header includes the encryption type, the Payload includes relevant data, and the Signature contains a string that we use to validate the response. All of this is outside the scope of this article... although if you're interested in pursuing the code into something workable you'll want to read JWT.io .

The Payload will often contain an Access Key. However, in the case of SalesTrekker, the entire JWT string is used as a token while the Payload returns the iat (issued at time) and the JWT exp (expiry time).

If you use an invalid token (JWT) in your requests you'll normally have an array returned with details of the error.

1
Array
2
(
3
    [errors] => Array
4
        (
5
            [0] => Array
6
                (
7
                    [message] => Error Message
8
                    [extensions] => Array
9
                        (
10
                            [code] => Error Code Here
11
                        )
12
 
13
                )
14
 
15
        )
16
 
17
)

So, skipping the validation of the signature we'll look at just a few basic requests. The following function is for demonstration purposes only, it uses a fixed JSON string, and it shouldn't be used in any production tool.

1
<?php 
2
/*
3
 Query SalesTrekker GraphQL API
4
 https://www.beliefmedia.com.au/salestrekker-api
5
*/
6
 
7
function beliefmedia_salestrekker_graphql($action = '') {
8
 
9
  $url = 'https://dev.salestrekker.com/graphql';
10
 
11
  /* Function here to retrieve the cached JWT access token */
12
  $accesstoken = 'your-full-jwt-token-string';
13
 
14
  switch ($action) {
15
 
16
     case 'workflows':
17
        $data = '{"query":"query {\n  workflows {\n    id\n    name\n    isActive\n    stages {\n      name\n    }\n  }\n}\n"}';
18
        break;
19
 
20
     case 'users':
21
        $data = '{"query":"query {\n  accounts {\n    id\n    idOwner\n    user {\n      firstName\n      lastName\n      eMail\n    }\n  }\n}"}';
22
        break;
23
 
24
     case 'contacts':
25
        $data = '{"query":"query {\n  contacts {\n    person {\n      contact {\n        primaryCode\n        primary\n      }\n      information {\n        firstName\n        familyName\n      }\n    }\n  }\n}\n"}';
26
        break;
27
 
28
     default:
29
        return false;
30
 
31
  }
32
 
33
  /* Curl Request */
34
  $ch = curl_init();
35
 
36
  /* Get fields */
37
  curl_setopt($ch, CURLOPT_URL, $url);
38
  curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
39
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
40
  curl_setopt($ch, CURLOPT_TIMEOUT, 30);
41
  curl_setopt($ch, CURLOPT_POST, true);
42
  curl_setopt($ch, CURLOPT_ENCODING, '');
43
  curl_setopt($ch, CURLOPT_HTTPHEADER, array(
44
    'User-Agent: BeliefMedia/1.0',
45
    'Accept-Encoding: gzip, deflate, br',
46
    'Content-Type: application/json',
47
    'Origin: https://beliefmedia.net',
48
    'Authorization: Bearer ' . $accesstoken,
49
    'Connection: Keep-Alive',
50
    'Content-Length:' . strlen($data)
51
  ));
52
 
53
  /* Execute */
54
  $result = curl_exec($ch);
55
 
56
  /* GraphQL will usually return an error property - 200 normally returned */
57
  $response_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
58
  if ($response_code != '200') {
59
 /* Do something if CURL screws the pooch */
60
 file_put_contents(time() . '-' . $response_code . '.txt', curl_error($ch));
61
 return false;
62
  }
63
 
64
  /* Close CURL */
65
  curl_close($ch);
66
 
67
  $return = json_decode($result, true);
68
 
69
 return $return;
70
}

The $accesstoken variable should be replaced with a function that retrieves a valid token or obtains a new token. The library we've written for SalesTrekker obviously does this both in the client application and on our Platform.

If we were to request the various workflows associated with token privileges we would use the following:

1
$result = beliefmedia_salestrekker_graphql($action = 'workflows');

A snapshot of the response array is as follows:

SalesTrekker Workflow GraphQL Response

SalesTrekker Workflow GraphQL Response.

The workflow query is one where the advantages of GraphQL become more evident. If we were querying all the workflows associated with a user via the depreciated API (V1) it wouldn't be uncommon to return at least 10 or 12 individual workflow IDs. We'd then have to query the stages of each workflow separately resulting in as many requests. Using GraphQL it's just one simple and fast request to return all data.

The contacts request is useful for a number of reasons, not the least of which is compiling necessary data for SMS messages. While text messages can be sent through SalesTrekker for a fee, there may be times when we'll have to segregate audiences in a manner that the platform doesn't provide. We retrieved about 4500 contacts from the development platform in a little over 5 seconds. In reality you'll want to apply your own style of pagination via the API.

Our demonstration function is rather clumsy in nature and was only used to illustrate a concept. We've pre-formatted various JSON strings which negate the effectiveness of the query language; however, there are times - such as some of the features we include in our Client Plugin BeliefMedia Client Plugin - where queries are always the same. In reality you'll likely create an array of data, check for required fields, and parse them into a formatted request.

Conclusion

The code on this page was provided for information purposes only. It's far from best practice and simply demonstrates the beginnings of a bigger-picture solution.

Many "marketers" talk about automation but very few know what it actually means. A CRM and your marketing tools should be seamlessly integrated in manner that eliminates double data entry and removes manual actions when automation provides a solution. Sadly, we're the only finance marketing company that manages leads in a manner that resembles anything resembling best-practice; most brokers that have sought the advice of "gurus" are left with little to no business automation to show for their investment.

As with all our integrated software, all our clients receive a lifetime licence for any and all updates to our web-based SalesTrekker features. Whenever an update is made in the future the new product is immediately made available to clients.

■ ■ ■

 
Download our complimentary 650-page guide on marketing for mortgage brokers. We'll show you exactly how we generate billions in volume for our clients.
Finance Guide, Cropped Top and Bottom
  Timezone: 1 · [ CHANGE ]

RELATED READING

Like this article?

Share on Facebook
Share on Twitter
Share on Linkdin
Share on Pinterest

Leave a comment