Search code examples
pythonhttpsetrade-api

Use Etrade API's query parameters returns unauthorized (401)


I cannot understand how to properly use the query parameters using Etrade's production API. Regardless of the query parameter used, the response is always unauthorized. Here's the documentation relevant to this example. Most of the code is taken from the Python example on this page.

I receive a 200 response without the parameter and 401 when adding the parameter sortOrder=ASC.

import configparser
from rauth import OAuth1Service
import webbrowser


# loading configuration file
config = configparser.ConfigParser()
config.read("etrade_python_client/config.ini")

etrade = OAuth1Service(
        name="etrade",
        consumer_key=config["DEFAULT"]["PROD_KEY"],
        consumer_secret=config["DEFAULT"]["PROD_SECRET"],
        request_token_url="https://api.etrade.com/oauth/request_token",
        access_token_url="https://api.etrade.com/oauth/access_token",
        authorize_url="https://us.etrade.com/e/t/etws/authorize?key={}&token={}",
        base_url="https://api.etrade.com")

request_token, request_token_secret = etrade.get_request_token(params={"oauth_callback": "oob", "format": "json"})
authorize_url = etrade.authorize_url.format(etrade.consumer_key, request_token)
webbrowser.open(authorize_url)

The previous line opens a web browser which I navigate to and copy the code and store it as text_code.

text_code = "<copy-code-from-web-browser>"
session = etrade.get_auth_session(request_token, request_token_secret, params={"oauth_verifier": text_code})

# get account info
url_account = "https://api.etrade.com/v1/accounts/list.json"
data_account = session.get(url_account, header_auth=True).json()

# store account id key
account_id_key = res["AccountListResponse"]["Accounts"]["Account"][0]["accountIdKey"]

# get portfolio and specify sortOrder
url_portfolio = "https://api.etrade.com/v1/accounts/{}/portfolio?sortOrder=ASC".format(account_id_key)
data_portfolio = session.get(url_portfolio, header_auth=True)
print(data_portfolio)
>>> <Response [401]>
# get portfolio and do not specify sort order    
url_portfolio = "https://api.etrade.com/v1/accounts/{}/portfolio".format(account_id_key)
data_portfolio = session.get(url_portfolio, header_auth=True)
print(data_portfolio)

>>> <Response [200]>

Has anyone else ran into this issue? I'm thinking I must not be passing the query parameters correctly.


Solution

  • The documentation on their site seems to not tell how to do that, but they provide an example python script which I hoped would include hints. And it kind of does, but I can't verify them as I don't have such an account. Please let us know, if either suggestion worked or you found another solution.

    While the example for a get to the portfolio endpoint they give looks like:

    def portfolio(self):    
        # URL for the API endpoint
        url =self.base_url + "/v1/accounts/" + self.account["accountIdKey"] + "/portfolio.json"
    
        # Make API call for GET request
        response = self.session.get(url, header_auth=True)
    

    There are other examples such as a get to balance, which might be relevant to your question:

    def balance(self):
        # URL for the API endpoint
        url = self.base_url + "/v1/accounts/" + self.account["accountIdKey"] + "/balance.json"
    
        # Add parameters and header information
        params = {"instType": self.account["institutionType"], "realTimeNAV": "true"}
        headers = {"consumerkey": config["DEFAULT"]["CONSUMER_KEY"]}
    
        # Make API call for GET request
        response = self.session.get(url, header_auth=True, params=params, headers=headers)
    

    Here we can see that params=params would be accept.

    So what I'd try would be something like this for your request:

    # get portfolio and specify sortOrder
    url_portfolio = "https://api.etrade.com/v1/account/{}/portfolio".format(account_id_key)
    params = {'sortOrder':'ASC'}
    data_portfolio = session.get(url_portfolio, params=params, header_auth=True)
    print(data_portfolio)
    

    Also, I'd consider the possibility that for sortOrder to be used correctly, you may need to provide a param for sortBy as well (acceptable values are in the doc you linked).