Quickstart Guide

This page is a walkthrough of getting a MarketMedians and Pay Report from Jobalyzer using Python.

Python

Reports

As documented in greater depth in Access Patterns, there are three pieces to successfully getting information out of the Jobalyzer service:

  • Authentication

  • Request Submission

  • Result Retrieval

The request for authentication is as follows:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import requests
import time


auth_url = 'https://accounts.payscale.com'
jobalyzer_url = 'https://jobalyzer.payscale.com'
generate_reports_url = f'{jobalyzer_url}/jobalyzer/v2/reports'
get_token_url = f'{auth_url}/connect/token'
client_id = '<your-client-id>'
client_secret = '<your-client-secret>'

# get oauth token using given clientId and clientSecret
payload = {
  'grant_type': 'client_credentials',
  'scope': 'jobalyzer',
  'client_id': client_id,
  'client_secret': client_secret
}
token_response = requests.post(get_token_url, data=payload)
token = None
if token_response.status_code == 200:
    token = token_response.json()['access_token']
else:
    print(f'failed to get token: {token_response.text}')

# make a request for reports using the new token
data = {
  "customerId": client_id,
  "user": client_id,
  "AutoResolveJobTitle": True, # optional, tries to automatch submitted job title
  "requestedReports": ["yoe", "pay"], # note that API limitations count per report, not request. This counts as 2 reports.
  "answers": {
    "JobTitle": "Software Developer",
    "City": "Seattle", # optional
    "State": "Washington", # optional
    "Country": "United States",
    "YearsExperience": 5, # optional, effects Pay report
    "HighestDegreeEarned": "Bachelor's Degree", # optional. Options include: "GED or High School Diploma", "Associate's Degree", "Bachelor's Degree",
        # "Master's Degree (non-MBA)", "Master of Business Administration (MBA)", "Juris Doctor (JD), Master of Jurisprudence, or Master of Law (LLM)",
        # "Doctorate (PhD)", "Doctor of Medicine (MD)"
    "Skills": ["Python", "JavaScript"] # optional
  }
}


headers = {'Authorization': f'Bearer {token}'}
request_response = requests.post(generate_reports_url, json=data, headers=headers)

# parse the returned links to receive the reports
print(request_response.json())
yoe_report_url = request_response.json()['Links']['YearsExperienceReport']
pay_report_url = request_response.json()['Links']['PayReport']

# request the completed reports until a 200 is returned
report_urls = {'Years of Experience': yoe_report_url,
             'Pay': pay_report_url}
reports = {}
for key in report_urls.keys():
    while reports.get(key) is None:
        response = requests.get(f'{report_urls[key]}?customerId={client_id}&user={client_id}', headers=headers)
        if response.status_code == 200:
            print(f'{key} report returned.')
            reports[key] = response.json()

        elif response.status_code == 202:
            print(f'{key} not ready, sleeping')
            time.sleep(response.json()['RetryAfterMilliseconds']/1000)
        else:
            print(f'failed for some other reason: {response.text}')
            break

print(reports)

The above code first gets an access token from Payscale's identity server using the provided clientId and clientSecret. This token must be included in the headers of any request to this service. It is good for 10 minutes, after which another must be fetched.

Next, the code creates a request. The request is passed as a json to the Generate Reports endpoint. The request is made of 4 parts:

  • customerId: Required, the client ID supplied by Payscale

  • user: Required, this can be any string, but is needed again to fetch the results.

  • requestedReports: Required, this is the number of reports which should be run. The reports listed here will change the required answers.

  • answers: Required, a key-value pair of QuestionIds and valid values for each of those QuestionIds. Invalid answers will return a 400-level error.

Once this request is submitted, the returned value looks like this:

{
    "Links": {
        "Self": "https://jobalyzer.payscale.com/jobalyzer/v2/reports/<unique-ID>",
        "PayReport": "https://jobalyzer.payscale.com/jobalyzer/v1/reports/<unique-ID>/pay",
        "YearsExperienceReport": "https://jobalyzer.payscale.com/jobalyzer/v2/reports/<unique-ID>/yoe",
    },
    "Warnings": null,
    "Errors": null
}

Notice that all of the potential reports are included, but do not contain a target url if they are not requested.

For each of the requested reports, the completed report can be fetched from the supplied link. Again, the headers must be included, and the customerId and user must be supplied as a querystring, as shown in the code.

Skills

A minimal application in Python looks like the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import requests
import time


auth_url = 'https://accounts.payscale.com'
jobalyzer_url = 'https://jobalyzer.payscale.com'
skills_url = f'{jobalyzer_url}/jobalyzer/v1/impact/skills'
get_token_url = f'{auth_url}/connect/token'
client_id = '<your-client-id>'
client_secret = '<your-client-secret>'

# get oauth token using given clientId and clientSecret
payload = {
  'grant_type': 'client_credentials',
  'scope': 'jobalyzer',
  'client_id': client_id,
  'client_secret': client_secret
}
token_response = requests.post(get_token_url, data=payload)
token = None
if token_response.status_code == 200:
    token = token_response.json()['access_token']
else:
    print(f'failed to get token: {token_response.text}')

job_title = 'Software Developer'
request_url = f'{skills_url}?customerId={client_id}&user={client_id}&jobTitle={job_title}&autoResolveJobTitle=True'

# get the synchronous Skill Impact using a get request with the Authorization Token
headers = {'Authorization': f'Bearer {token}'}
response = requests.get(request_url, headers=headers)
print(response.json())

The response will look like the following:

{
"Answers": {
    <skill 1>: {
        "ProfileCount": <int>,
        "PercentReporting": <float>,
        "MedianBasePay": <float>,
        "PayDifferential": <float,
        "PayDifferentialPercentage": <float>
    },
    <skill 2>: {
        "ProfileCount": <int>,
        "PercentReporting": <float>,
        "MedianBasePay": <float>,
        "PayDifferential": <float,
        "PayDifferentialPercentage": <float>
    },
    ...
    <skill n>: {
        "ProfileCount": <int>,
        "PercentReporting": <float>,
        "MedianBasePay": <float>,
        "PayDifferential": <float,
        "PayDifferentialPercentage": <float>
    },
}

Certifications

A minimal application in Python looks like the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import requests
import time


auth_url = 'https://accounts.payscale.com'
jobalyzer_url = 'https://jobalyzer.payscale.com'
certs_url = f'{jobalyzer_url}/jobalyzer/v1/impact/certs'
get_token_url = f'{auth_url}/connect/token'
client_id = '<your-client-id>'
client_secret = '<your-client-secret>'

# get oauth token using given clientId and clientSecret
payload = {
  'grant_type': 'client_credentials',
  'scope': 'jobalyzer',
  'client_id': client_id,
  'client_secret': client_secret
}
token_response = requests.post(get_token_url, data=payload)
token = None
if token_response.status_code == 200:
    token = token_response.json()['access_token']
else:
    print(f'failed to get token: {token_response.text}')

job_title = 'Software Developer'
request_url = f'{certs_url}?customerId={client_id}&user={client_id}&jobTitle={job_title}&autoResolveJobTitle=True'

# get the synchronous Cert Impact using a get request with the Authorization Token
headers = {'Authorization': f'Bearer {token}'}
response = requests.get(request_url, headers=headers)
print(response.json())

The response will look like the following:

{
"Answers": {
    <cert 1>: {
        "ProfileCount": <int>,
        "PercentReporting": <float>,
        "MedianBasePay": <float>,
        "PayDifferential": <float,
        "PayDifferentialPercentage": <float>
    },
    <cert 2>: {
        "ProfileCount": <int>,
        "PercentReporting": <float>,
        "MedianBasePay": <float>,
        "PayDifferential": <float,
        "PayDifferentialPercentage": <float>
    },
    ...
    <cert n>: {
        "ProfileCount": <int>,
        "PercentReporting": <float>,
        "MedianBasePay": <float>,
        "PayDifferential": <float,
        "PayDifferentialPercentage": <float>
    },
}

Education

A minimal application in Python looks like the following:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import requests
import time


auth_url = 'https://accounts.payscale.com'
jobalyzer_url = 'https://jobalyzer.payscale.com'
education_url = f'{jobalyzer_url}/jobalyzer/v1/impact/education'
get_token_url = f'{auth_url}/connect/token'
client_id = '<your-client-id>'
client_secret = '<your-client-secret>'

# get oauth token using given clientId and clientSecret
payload = {
  'grant_type': 'client_credentials',
  'scope': 'jobalyzer',
  'client_id': client_id,
  'client_secret': client_secret
}
token_response = requests.post(get_token_url, data=payload)
token = None
if token_response.status_code == 200:
    token = token_response.json()['access_token']
else:
    print(f'failed to get token: {token_response.text}')

job_title = 'Software Developer'
request_url = f'{education_url}?customerId={client_id}&user={client_id}&jobTitle={job_title}&autoResolveJobTitle=True'

# get the synchronous Education Impact using a get request with the Authorization Token
headers = {'Authorization': f'Bearer {token}'}
response = requests.get(request_url, headers=headers)
print(response.json())

The response will look like the following:

{
"Answers": {
    <education 1>: {
        "ProfileCount": <int>,
        "PercentReporting": <float>,
        "MedianBasePay": <float>,
        "PayDifferential": <float,
        "PayDifferentialPercentage": <float>
    },
    <education 2>: {
        "ProfileCount": <int>,
        "PercentReporting": <float>,
        "MedianBasePay": <float>,
        "PayDifferential": <float,
        "PayDifferentialPercentage": <float>
    },
    ...
    <education n>: {
        "ProfileCount": <int>,
        "PercentReporting": <float>,
        "MedianBasePay": <float>,
        "PayDifferential": <float,
        "PayDifferentialPercentage": <float>
    },
}

C#

We have a minimal C# application that is available as a zip library here jobalyzer_client

Reports

Following a similar pattern to the above Python code, the C# code below using the above client is a great starting point:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static void Main(string[] args)
    {
        var environment = new HostingEnvironment
        {
            EnvironmentName = "Test",
            ContentRootPath = Directory.GetCurrentDirectory()
        };
        var configuration = BuildConfiguration(environment);
        var serviceProvider = ConfigureServices(configuration, environment);
        var jobalyzerClient = (IJobalyzerWrapper)serviceProvider.GetService(typeof(IJobalyzerWrapper));

        // Generate report here for simplicity since this is just an example
        var requestedReports = new string[] { "pay" };
        var answersDict = new Dictionary<string, object>
        {
            ["JobTitle"] = "Software Developer",
            ["City"] = "Seattle",
            ["State"] = "Washington",
            ["Country"] = "United States",
            ["Skills"] = new string[] { "Java", "Python" }
        };
        var report = jobalyzerClient.GeneratePayReport(requestedReports, answersDict, "TestCustomer", "TestUSer");
        report.Wait();

        Console.WriteLine(JsonConvert.SerializeObject(report.Result));

        Console.WriteLine("Press enter to continue...");
        Console.ReadLine();
    }

Integration

Warning

Report credits can be rapidly consumed during integration with the jobalyzer API. To address that, the API supports a test flag.

Reports

The test flag should be specified at the root level of the request, as shown in the following example:

{
  "CustomerId": "<clientId>",
  "User": "<clientId>",
  "RequestedReports": [
    "pay", "yoe"
  ],
  "Test": true,
  "Answers": {
    "Location": {
      "Country": "United States"
    }
  }
}

Skills

The test flag should be appended to the querystring of the request, as shown in the following example:

request_url = f'{skills_url}?customerId={client_id}&user={client_id}&jobTitle={job_title}&autoResolveJobTitle=True&test=True

Note

The data returned from a request containing a test flag value of true is random, and is not impacted by the answer values submitted.

Certifications

The test flag should be appended to the querystring of the request, as shown in the following example:

request_url = f'{certs_url}?customerId={client_id}&user={client_id}&jobTitle={job_title}&autoResolveJobTitle=True&test=True

Note

The data returned from a request containing a test flag value of true is random, and is not impacted by the answer values submitted.

Troubleshooting

  • I'm getting KeyError: "Links" not found

    • It's likely that you're getting an error. It's possible that you're out of API hits. The expected error message for this is User requested more reports than they have available

  • I'm getting some other error