Access Patterns =============== Due to Jobalyzer's async access, some patterns may be useful as a reference. Authentication -------------- Authentication is handled by the service at the URL :code:`https://accounts.payscale.com/connect/token`, as shown in the code below. The response from this system is a json object containing the following keys: * access_token: This is your access token, good for 10 minutes. * expires_in: This is how long your token is good for, in seconds. Generally 3600. * token_type: This is how you will use your token. Generally, this is "Bearer" type. * scope: This is the service your token is good for. Generally, this is just Jobalyzer. .. code-block:: python import requests import time auth_url = 'https://accounts.payscale.com' 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) if token_response.status_code == 200: token = token_response.json()['access_token'] else: print(f'failed to get token: {token_response.text}') Async Access ------------ Jobalyzer is a completely asynchronous service, meaning that the requests for generating a report and the requests for pulling down a report will complete whether the report is ready or not. In order to successfully retrieve a completed report, you must wait until the returned status code is `200`. First, we will take a look at submitting the Report Generation Request: .. code-block:: python import requests import time jobalyzer_url = 'https://jobalyzer.payscale.com' generate_reports_url = f'{jobalyzer_url}/jobalyzer/v1/reports' client_id = '' client_secret = '' # make a request for reports using the new token # 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"], "answers": { "JobTitle": "Software Developer", "City": "Seattle", # optional "State": "Washington", # optional "Country": "United States", "YearsExperience": 5, # optional, effects Pay report "HighestDegreeEarned": "Bachelors" # optional } } headers = {'Authorization': f'Bearer {token}'} request_response = requests.post(generate_reports_url, json=data, headers=headers) The response will look like the following: .. 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 } Any errors will be present in "Errors". Common errors include: * Submitting an Unconfirmed Answer. This means that the answer does not appear in our database, and cannot be used to describe our data. * Expired token: This will result in a 401 Unauthorized error. Please refresh your token and try again. Retrying -------- When the report links are generated, the reports are not done. Occasionally, depending upon load, there can be a minor delay between the link being generated and the report being ready. In these instances, it's fine to keep hitting the same link until the report is returned. .. code-block:: python # parse the returned links to receive the reports 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) .. Note:: In both instances, a json object will be returned, and the status code should be used to differentiate between these events. Once a report is collected, it can be collected again for a period of time, so expecting an error after a successful return is also not a viable strategy. Sync Access ----------- Some endpoints are synchronous, like the `/jobalyzer/v1/impact/skills` and `/jobalyzer/v1/impact/certs` endpoints. These still require the authentication token, but do not require polling for the result.