Quickstart Guide ================ This page is a walkthrough of getting a MarketMedians and Pay Report from Jobalyzer using Python. .. _troubleshooting: troubleshooting.html .. _Access Patterns: patterns.html 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: .. code-block:: python :linenos: 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 = '' 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: .. code-block:: JSON { "Links": { "Self": "https://jobalyzer.payscale.com/jobalyzer/v2/reports/", "PayReport": "https://jobalyzer.payscale.com/jobalyzer/v1/reports//pay", "YearsExperienceReport": "https://jobalyzer.payscale.com/jobalyzer/v2/reports//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: .. code-block:: python :linenos: 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 = '' 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: .. code-block:: javascript { "Answers": { : { "ProfileCount": , "PercentReporting": , "MedianBasePay": , "PayDifferential": }, : { "ProfileCount": , "PercentReporting": , "MedianBasePay": , "PayDifferential": }, ... : { "ProfileCount": , "PercentReporting": , "MedianBasePay": , "PayDifferential": }, } Certifications ^^^^^^^^^^^^^^ A minimal application in Python looks like the following: .. code-block:: python :linenos: 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 = '' 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: .. code-block:: javascript { "Answers": { : { "ProfileCount": , "PercentReporting": , "MedianBasePay": , "PayDifferential": }, : { "ProfileCount": , "PercentReporting": , "MedianBasePay": , "PayDifferential": }, ... : { "ProfileCount": , "PercentReporting": , "MedianBasePay": , "PayDifferential": }, } Education ^^^^^^ A minimal application in Python looks like the following: .. code-block:: python :linenos: 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 = '' 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: .. code-block:: javascript { "Answers": { : { "ProfileCount": , "PercentReporting": , "MedianBasePay": , "PayDifferential": }, : { "ProfileCount": , "PercentReporting": , "MedianBasePay": , "PayDifferential": }, ... : { "ProfileCount": , "PercentReporting": , "MedianBasePay": , "PayDifferential": }, } C# -- We have a minimal C# application that is available as a zip library here :download:`jobalyzer_client <../_static/jobalyzer-csharpclient-example.zip>` Reports ^^^^^^^ Following a similar pattern to the above Python code, the C# code below using the above client is a great starting point: .. code-block:: csharp :linenos: 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 { ["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: .. code-block:: javascript :emphasize-lines: 7 { "CustomerId": "", "User": "", "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: .. code-block:: python 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: .. code-block:: python 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 :code:`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 :code:`User requested more reports than they have available` * I'm getting some other error * Check out troubleshooting_