wb.login() is returning 403
Today, logging into Webull via the Python webull library started failing. The POST to the login endpoint returns HTTP 403 with a non-JSON body (or empty body), which then causes response.json() to raise JSONDecodeError.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.10/dist-packages/webull/webull.py", line 171, in login
result = response.json()
File "/usr/lib/python3/dist-packages/requests/models.py", line 900, in json
return complexjson.loads(self.text, **kwargs)
File "/usr/lib/python3.10/json/__init__.py", line 346, in loads
return _default_decoder.decode(s)
File "/usr/lib/python3.10/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/usr/lib/python3.10/json/decoder.py", line 355, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
I have printed out the response.
response = requests.post(self._urls.login(), json=data, headers=headers, timeout=self.timeout)
print(response)
result = response.json()
It returned <Response [403]>
Changing the _did parameter did not help.
Could you check please?
Same issue here --
Looks like all endpoints from endpoints.py doesn't work:
endpoints=(
"https://infoapi.webull.com/api"
"https://quoteapi.webullbroker.com/api"
"https://quotes-gw.webullbroker.com/api"
"https://act.webullbroker.com/webull-paper-center/api"
"https://quoteapi.webullbroker.com/api"
"https://securitiesapi.webullbroker.com/api"
"https://tradeapi.webullbroker.com/api/trade"
"https://userapi.webull.com/api"
"https://userapi.webullbroker.com/api"
"https://ustrade.webullfinance.com/api"
"https://act.webullfintech.com/webull-paper-center/api"
"https://quotes-gw.webullfintech.com/api"
"https://u1suser.webullfintech.com/api"
"https://trade.webullfintech.com/api"
"https://ustrade.webullbroker.com/api"
"https://securitiesapi.webullfintech.com/api"
)
for url in "${endpoints[@]}"; do
status=$(curl -s -o /dev/null -w "%{http_code}" --max-time 5 "$url")
if [ "$status" -eq 200 ]; then
echo "[OK] $url"
else
echo "[ERROR] $url (HTTP $status)"
fi
done
[ERROR] https://infoapi.webull.com/api (HTTP 503)
[ERROR] https://quoteapi.webullbroker.com/api (HTTP 503)
[ERROR] https://quotes-gw.webullbroker.com/api (HTTP 404)
[ERROR] https://act.webullbroker.com/webull-paper-center/api (HTTP 404)
[ERROR] https://quoteapi.webullbroker.com/api (HTTP 503)
[ERROR] https://securitiesapi.webullbroker.com/api (HTTP 503)
[ERROR] https://tradeapi.webullbroker.com/api/trade (HTTP 404)
[ERROR] https://userapi.webull.com/api (HTTP 503)
[ERROR] https://userapi.webullbroker.com/api (HTTP 503)
[ERROR] https://ustrade.webullfinance.com/api (HTTP 404)
[ERROR] https://act.webullfintech.com/webull-paper-center/api (HTTP 404)
[ERROR] https://quotes-gw.webullfintech.com/api (HTTP 404)
[ERROR] https://u1suser.webullfintech.com/api (HTTP 404)
you need to enhance a retry mechanism on authentication, try this , it will work :
# Authentication with retry mechanism
def authenticate_webull(max_retries=3, retry_delay=2):
"""Authenticate with Webull API with retry mechanism"""
for attempt in range(max_retries):
try:
logger.info("Authenticating with Webull API")
# First check if already logged in
if wb.is_logged_in():
logger.info("Already logged in to Webull")
return True
# Get trade token and login
wb.get_trade_token(pwd_unlock)
res = wb.login(wb_email, wb_passcode, 'web', save_token=True)
if wb.is_logged_in():
logger.info("Successfully authenticated with Webull")
return True
else:
logger.warning(f"Login returned success but is_logged_in check failed (attempt {attempt+1}/{max_retries})")
except Exception as e:
logger.error(f"Authentication error (attempt {attempt+1}/{max_retries}): {str(e)}")
if attempt < max_retries - 1:
logger.info(f"Retrying in {retry_delay} seconds...")
time.sleep(retry_delay)
else:
logger.error("All authentication attempts failed")
return False
return False
from webull import webull
import os
import sys
import time
import logging
from requests.exceptions import JSONDecodeError
# --- Basic Logging Setup ---
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
stream=sys.stdout,
)
# --- Main Script ---
wb = webull()
username = os.getenv("WB_USERNAME")
password = os.getenv("WB_PASSWORD")
# Print confirmation that credentials are set
if username and password:
uname_tail = username[-3:] if len(username) >= 3 else username
logging.info(f"Using WB_USERNAME ending in: ...{uname_tail}")
logging.info("WB_PASSWORD is set.")
else:
logging.error("Webull login failed: missing WB_USERNAME or WB_PASSWORD environment variables.")
sys.exit(1)
def authenticate_webull(max_retries=3, retry_delay=5):
"""Authenticate with Webull API with a robust retry mechanism."""
for attempt in range(max_retries):
try:
logging.info(f"Attempting to log into Webull (Attempt {attempt + 1}/{max_retries})...")
# The login call itself is the primary action.
response = wb.login(username, password)
logging.info(f"Login API call successful. Response: {response}")
# To truly verify, let's try a post-login action.
logging.info("Verifying login with a data request (get_account)...")
account_info = wb.get_account()
if account_info and 'accountMembers' in account_info:
logging.info("Successfully authenticated with Webull and verified with account data.")
return True
else:
logging.warning(f"Login seemed to succeed, but account verification failed. Response: {account_info}")
except JSONDecodeError as e:
logging.error(f"Authentication error (attempt {attempt+1}/{max_retries}): The server returned an invalid response (not JSON).")
logging.error(f"Server Response Text that caused the error: {e.doc}")
except Exception as e:
logging.error(f"An unexpected authentication error occurred (attempt {attempt+1}/{max_retries}): {str(e)}")
if attempt < max_retries - 1:
logging.info(f"Retrying in {retry_delay} seconds...")
time.sleep(retry_delay)
else:
logging.error("All authentication attempts failed.")
return False
return False
# --- Execute the authentication ---
if __name__ == "__main__":
if authenticate_webull():
print("\n✅ Webull Login Test Passed!")
# Example of a next step:
try:
quote = wb.get_quote('AAPL')
print(f"\nSuccessfully fetched a quote for AAPL: {quote.get('name')} is at ${quote.get('close')}")
except Exception as e:
print(f"\n⚠️ Could not fetch quote after login: {e}")
else:
print("\n❌ Webull Login Test Failed.")
sys.exit(1)
2025-09-16 07:48:07,014 - INFO - Using WB_USERNAME ending in: ...com 2025-09-16 07:48:07,014 - INFO - WB_PASSWORD is set. 2025-09-16 07:48:07,014 - INFO - Attempting to log into Webull (Attempt 1/3)... 2025-09-16 07:48:07,127 - ERROR - Authentication error (attempt 1/3): The server returned an invalid response (not JSON). 2025-09-16 07:48:07,127 - ERROR - Server Response Text that caused the error: Illegal Client 2025-09-16 07:48:07,128 - INFO - Retrying in 5 seconds... 2025-09-16 07:48:12,133 - INFO - Attempting to log into Webull (Attempt 2/3)... 2025-09-16 07:48:12,315 - ERROR - Authentication error (attempt 2/3): The server returned an invalid response (not JSON). 2025-09-16 07:48:12,315 - ERROR - Server Response Text that caused the error: Illegal Client 2025-09-16 07:48:12,317 - INFO - Retrying in 5 seconds... 2025-09-16 07:48:17,320 - INFO - Attempting to log into Webull (Attempt 3/3)... 2025-09-16 07:48:17,490 - ERROR - Authentication error (attempt 3/3): The server returned an invalid response (not JSON). 2025-09-16 07:48:17,490 - ERROR - Server Response Text that caused the error: Illegal Client 2025-09-16 07:48:17,491 - ERROR - All authentication attempts failed.
❌ Webull Login Test Failed.
happening on my end too, retry did not help
your code lacks one important step , you will still need to give did/access_token regularly ,even without this retry:
# Initialize Webull API
wb = webull()
wb._set_did(wb_did)
wb._access_token = wb_access_token
from webull import webull import os import sys import time import logging from requests.exceptions import JSONDecodeError # --- Basic Logging Setup --- logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', stream=sys.stdout, ) # --- Main Script --- wb = webull() username = os.getenv("WB_USERNAME") password = os.getenv("WB_PASSWORD") # Print confirmation that credentials are set if username and password: uname_tail = username[-3:] if len(username) >= 3 else username logging.info(f"Using WB_USERNAME ending in: ...{uname_tail}") logging.info("WB_PASSWORD is set.") else: logging.error("Webull login failed: missing WB_USERNAME or WB_PASSWORD environment variables.") sys.exit(1) def authenticate_webull(max_retries=3, retry_delay=5): """Authenticate with Webull API with a robust retry mechanism.""" for attempt in range(max_retries): try: logging.info(f"Attempting to log into Webull (Attempt {attempt + 1}/{max_retries})...") # The login call itself is the primary action. response = wb.login(username, password) logging.info(f"Login API call successful. Response: {response}") # To truly verify, let's try a post-login action. logging.info("Verifying login with a data request (get_account)...") account_info = wb.get_account() if account_info and 'accountMembers' in account_info: logging.info("Successfully authenticated with Webull and verified with account data.") return True else: logging.warning(f"Login seemed to succeed, but account verification failed. Response: {account_info}") except JSONDecodeError as e: logging.error(f"Authentication error (attempt {attempt+1}/{max_retries}): The server returned an invalid response (not JSON).") logging.error(f"Server Response Text that caused the error: {e.doc}") except Exception as e: logging.error(f"An unexpected authentication error occurred (attempt {attempt+1}/{max_retries}): {str(e)}") if attempt < max_retries - 1: logging.info(f"Retrying in {retry_delay} seconds...") time.sleep(retry_delay) else: logging.error("All authentication attempts failed.") return False return False # --- Execute the authentication --- if __name__ == "__main__": if authenticate_webull(): print("\n✅ Webull Login Test Passed!") # Example of a next step: try: quote = wb.get_quote('AAPL') print(f"\nSuccessfully fetched a quote for AAPL: {quote.get('name')} is at ${quote.get('close')}") except Exception as e: print(f"\n⚠️ Could not fetch quote after login: {e}") else: print("\n❌ Webull Login Test Failed.") sys.exit(1)2025-09-16 07:48:07,014 - INFO - Using WB_USERNAME ending in: ...com 2025-09-16 07:48:07,014 - INFO - WB_PASSWORD is set. 2025-09-16 07:48:07,014 - INFO - Attempting to log into Webull (Attempt 1/3)... 2025-09-16 07:48:07,127 - ERROR - Authentication error (attempt 1/3): The server returned an invalid response (not JSON). 2025-09-16 07:48:07,127 - ERROR - Server Response Text that caused the error: Illegal Client 2025-09-16 07:48:07,128 - INFO - Retrying in 5 seconds... 2025-09-16 07:48:12,133 - INFO - Attempting to log into Webull (Attempt 2/3)... 2025-09-16 07:48:12,315 - ERROR - Authentication error (attempt 2/3): The server returned an invalid response (not JSON). 2025-09-16 07:48:12,315 - ERROR - Server Response Text that caused the error: Illegal Client 2025-09-16 07:48:12,317 - INFO - Retrying in 5 seconds... 2025-09-16 07:48:17,320 - INFO - Attempting to log into Webull (Attempt 3/3)... 2025-09-16 07:48:17,490 - ERROR - Authentication error (attempt 3/3): The server returned an invalid response (not JSON). 2025-09-16 07:48:17,490 - ERROR - Server Response Text that caused the error: Illegal Client 2025-09-16 07:48:17,491 - ERROR - All authentication attempts failed.
❌ Webull Login Test Failed.
your code lacks one important step , you will still need to give did/access_token regularly ,even without this retry:
# Initialize Webull API wb = webull() wb._set_did(wb_did) wb._access_token = wb_access_tokenfrom webull import webull import os import sys import time import logging from requests.exceptions import JSONDecodeError # --- Basic Logging Setup --- logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', stream=sys.stdout, ) # --- Main Script --- wb = webull() username = os.getenv("WB_USERNAME") password = os.getenv("WB_PASSWORD") # Print confirmation that credentials are set if username and password: uname_tail = username[-3:] if len(username) >= 3 else username logging.info(f"Using WB_USERNAME ending in: ...{uname_tail}") logging.info("WB_PASSWORD is set.") else: logging.error("Webull login failed: missing WB_USERNAME or WB_PASSWORD environment variables.") sys.exit(1) def authenticate_webull(max_retries=3, retry_delay=5): """Authenticate with Webull API with a robust retry mechanism.""" for attempt in range(max_retries): try: logging.info(f"Attempting to log into Webull (Attempt {attempt + 1}/{max_retries})...") # The login call itself is the primary action. response = wb.login(username, password) logging.info(f"Login API call successful. Response: {response}") # To truly verify, let's try a post-login action. logging.info("Verifying login with a data request (get_account)...") account_info = wb.get_account() if account_info and 'accountMembers' in account_info: logging.info("Successfully authenticated with Webull and verified with account data.") return True else: logging.warning(f"Login seemed to succeed, but account verification failed. Response: {account_info}") except JSONDecodeError as e: logging.error(f"Authentication error (attempt {attempt+1}/{max_retries}): The server returned an invalid response (not JSON).") logging.error(f"Server Response Text that caused the error: {e.doc}") except Exception as e: logging.error(f"An unexpected authentication error occurred (attempt {attempt+1}/{max_retries}): {str(e)}") if attempt < max_retries - 1: logging.info(f"Retrying in {retry_delay} seconds...") time.sleep(retry_delay) else: logging.error("All authentication attempts failed.") return False return False # --- Execute the authentication --- if __name__ == "__main__": if authenticate_webull(): print("\n✅ Webull Login Test Passed!") # Example of a next step: try: quote = wb.get_quote('AAPL') print(f"\nSuccessfully fetched a quote for AAPL: {quote.get('name')} is at ${quote.get('close')}") except Exception as e: print(f"\n⚠️ Could not fetch quote after login: {e}") else: print("\n❌ Webull Login Test Failed.") sys.exit(1)2025-09-16 07:48:07,014 - INFO - Using WB_USERNAME ending in: ...com 2025-09-16 07:48:07,014 - INFO - WB_PASSWORD is set. 2025-09-16 07:48:07,014 - INFO - Attempting to log into Webull (Attempt 1/3)... 2025-09-16 07:48:07,127 - ERROR - Authentication error (attempt 1/3): The server returned an invalid response (not JSON). 2025-09-16 07:48:07,127 - ERROR - Server Response Text that caused the error: Illegal Client 2025-09-16 07:48:07,128 - INFO - Retrying in 5 seconds... 2025-09-16 07:48:12,133 - INFO - Attempting to log into Webull (Attempt 2/3)... 2025-09-16 07:48:12,315 - ERROR - Authentication error (attempt 2/3): The server returned an invalid response (not JSON). 2025-09-16 07:48:12,315 - ERROR - Server Response Text that caused the error: Illegal Client 2025-09-16 07:48:12,317 - INFO - Retrying in 5 seconds... 2025-09-16 07:48:17,320 - INFO - Attempting to log into Webull (Attempt 3/3)... 2025-09-16 07:48:17,490 - ERROR - Authentication error (attempt 3/3): The server returned an invalid response (not JSON). 2025-09-16 07:48:17,490 - ERROR - Server Response Text that caused the error: Illegal Client 2025-09-16 07:48:17,491 - ERROR - All authentication attempts failed. ❌ Webull Login Test Failed.
I still get same error. The link return 503 error
yep, still 403 error:
2025-09-16 11:31:40,796 - ERROR - Authentication error (attempt 3/3): The server returned an invalid response (not JSON).
2025-09-16 11:31:40,796 - ERROR - Server Response Text that caused the error: Illegal Client
2025-09-16 11:31:40,798 - ERROR - All authentication attempts failed.
I don't know how it worked before, but I think they've added an additional check for some headers in the requests. Possibly related to passport.webull.com
I did some viewing of webull request. Here's what I've found for a new header set. x-sv, x-s, and reqid are what im unsure of. x-sv has been constant for me across different chrome instances. Reqid and x-s change every request. From what I can tell, these 2 are important for avoiding a 403. I am not knowledgeable enough about web code and could not find how these were generated
x-sv: a short constant value, consistent between requests, reqid: appears to be string based on 36 its with a length of 32. Changes with every request x-s: appears to be some hashed value. Changes with every request.
self._headers = { # modified 'appid': 'wb_web_passport', 'sec-ch-ua-platform': "Windows", 'device-type': 'Web', 'hl': 'en', 'sec-ch-ua': '"Chromium";v="140", "Not=A?Brand";v="24", "Google Chrome";v="140"', 'sec-ch-ua-mobile': '?0', 'app': 'global', 't_time': str(int(time.time() * 1000)), 'content-type': 'application/json', 'os': 'web', 'platform': 'web', 'osv': 'i9zh', 'did': self._get_did(), "ph": "Windows Chrome", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36", 'ver': '1.0.0', 'app-group': 'broker', 'accept': '/', 'accept-encoding': 'gzip, deflate, br, zstd', 'accept-language': 'en-US,en;q=0.9',
'x-sv': a short constant value, consistent between requests,
'x-s': appears to be some hashed value. Changes with every request
'reqid': appears to be string based on 36 its with a length of 32. Changes with every request
}
same issue for me since yesterday. Let us know if you find a fix.
There's no way to fix it unless someone knows how to crack the X_S. Theres a very very obfuscated javascript file within Webull, but I've had a hard time getting anything out of it.
There's no way to fix it unless someone knows how to crack the X_S. Theres a very very obfuscated javascript file within Webull, but I've had a hard time getting anything out of it.
What information are you trying to get out of X_S?
There's no way to fix it unless someone knows how to crack the X_S. Theres a very very obfuscated javascript file within Webull, but I've had a hard time getting anything out of it.
What information are you trying to get out of X_S?
It's the key header needed to pass authentication and not get an invalid client error. If we know how to generate it using the other headers, then we can properly log in.
any update on this?
Webull api is dead now
If you grab your own web traffic, you can get an access token and refresh token that enables API use again
If you grab your own web traffic, you can get an access token and refresh token that enables API use again
can you give an example
If you grab your own web traffic, you can get an access token and refresh token that enables API use again
can you give an example
I cannot give an actual example because that would allow you to access my account I use mitmweb, grab the request my computer sends to https://u1suser.webullfintech.com/api/user/v1/login/account/v2 In the response to the login is a JSON with a refresh token and access token. You can manually add these to the webull package using the api_login function. The login process is just to get these tokens.
If you grab your own web traffic, you can get an access token and refresh token that enables API use again
can you give an example
I cannot give an actual example because that would allow you to access my account I use mitmweb, grab the request my computer sends to https://u1suser.webullfintech.com/api/user/v1/login/account/v2 In the response to the login is a JSON with a refresh token and access token. You can manually add these to the webull package using the api_login function. The login process is just to get these tokens.
Could you show example in code (don't need set exactly your access token)? And how long live session with access token?
hmm maybe i did something wrong but i did find my refresh and access token by using mitmweb and put it in the api_login function but its still giving me Error initializing Webull client: Expecting value: line 1 column 1 (char 0)
Guys , let me clarify : this retry authentication is working perfectly. But you need to refresh/config your did/access_token correctly first , either retry or not . Dm me if you still have issue in authentication.
hmm maybe i did something wrong but i did find my refresh and access token by using mitmweb and put it in the api_login function but its still giving me Error initializing Webull client: Expecting value: line 1 column 1 (char 0)
You're right. I directly put my token into the webull class item. api_login seems to call some function that breaks. I had originally tested by just adding the token to the init. I think I'll have to modify the package a bit to make this easy to use
Once i load the the token into the webull object, it works fine for my purposes.
If you grab your own web traffic, you can get an access token and refresh token that enables API use again
can you give an example
I cannot give an actual example because that would allow you to access my account I use mitmweb, grab the request my computer sends to https://u1suser.webullfintech.com/api/user/v1/login/account/v2 In the response to the login is a JSON with a refresh token and access token. You can manually add these to the webull package using the api_login function. The login process is just to get these tokens.
Could you show example in code (don't need set exactly your access token)? And how long live session with access token?
I'm not sure what code I can send. I added my token directly to the webull init as the self._refresh_token. someone else pointed out the api_login doesnt actually work
Based on the webull webite response, the access token lasts about a week. My quick google of a refresh token says it should last long term.
I was able to get the login working by manually set the access token, refresh token, uuid, token expire date etc. My question is how often should we manually update this access token? Refresh token doesn't seem to change. I couldn't find token expire date, so I added a random date which actually works fine.
Below is how I updated the 'login' function in webull.py. I am not sure if there is any better way?
# response = requests.post(self._urls.login(), json=data, headers=headers, timeout=self.timeout)
# result = response.json()
# if 'accessToken' in result :
# self._access_token = result['accessToken']
# self._refresh_token = result['refreshToken']
# self._token_expire = result['tokenExpireTime']
# self._uuid = result['uuid']
# self._account_id = self.get_account_id()
# if save_token:
# self._save_token(result, token_path)
self._access_token = 'xxxxxxxxxxxxxxx'
self._refresh_token = 'xxxxxxxxxxxxxxxxxxxx'
self._token_expire = '2026-02-14T13:35:35.780+0000'
self._uuid = "xxxxxxxxxxxxxx"
self._account_id = 'xxxxxxxxxxx'
result = {
"accessToken": self._access_token,
"refreshToken": self._refresh_token,
"tokenExpireTime":self._token_expire,
"uuid": self._uuid,
}
access_token
Guys , let me clarify : this retry authentication is working perfectly. But you need to refresh/config your did/access_token correctly first , either retry or not . Dm me if you still have issue in authentication.
How often do we need to manually update the access token?
I was able to get the login working by manually set the access token, refresh token, uuid, token expire date etc. My question is how often should we manually update this access token? Refresh token doesn't seem to change. I couldn't find token expire date, so I added a random date which actually works fine.
Below is how I updated the 'login' function in webull.py. I am not sure if there is any better way?
# response = requests.post(self._urls.login(), json=data, headers=headers, timeout=self.timeout) # result = response.json() # if 'accessToken' in result : # self._access_token = result['accessToken'] # self._refresh_token = result['refreshToken'] # self._token_expire = result['tokenExpireTime'] # self._uuid = result['uuid'] # self._account_id = self.get_account_id() # if save_token: # self._save_token(result, token_path) self._access_token = 'xxxxxxxxxxxxxxx' self._refresh_token = 'xxxxxxxxxxxxxxxxxxxx' self._token_expire = '2026-02-14T13:35:35.780+0000' self._uuid = "xxxxxxxxxxxxxx" self._account_id = 'xxxxxxxxxxx' result = { "accessToken": self._access_token, "refreshToken": self._refresh_token, "tokenExpireTime":self._token_expire, "uuid": self._uuid, }
this worked thank you so much
by
I was able to get the login working by manually set the access token, refresh token, uuid, token expire date etc. My question is how often should we manually update this access token? Refresh token doesn't seem to change. I couldn't find token expire date, so I added a random date which actually works fine.
Below is how I updated the 'login' function in webull.py. I am not sure if there is any better way?
# response = requests.post(self._urls.login(), json=data, headers=headers, timeout=self.timeout) # result = response.json() # if 'accessToken' in result : # self._access_token = result['accessToken'] # self._refresh_token = result['refreshToken'] # self._token_expire = result['tokenExpireTime'] # self._uuid = result['uuid'] # self._account_id = self.get_account_id() # if save_token: # self._save_token(result, token_path) self._access_token = 'xxxxxxxxxxxxxxx' self._refresh_token = 'xxxxxxxxxxxxxxxxxxxx' self._token_expire = '2026-02-14T13:35:35.780+0000' self._uuid = "xxxxxxxxxxxxxx" self._account_id = 'xxxxxxxxxxx' result = { "accessToken": self._access_token, "refreshToken": self._refresh_token, "tokenExpireTime":self._token_expire, "uuid": self._uuid, }
by doing this, I can only get the account information, still can't place order. Anybody can advise?
by
I was able to get the login working by manually set the access token, refresh token, uuid, token expire date etc. My question is how often should we manually update this access token? Refresh token doesn't seem to change. I couldn't find token expire date, so I added a random date which actually works fine. Below is how I updated the 'login' function in webull.py. I am not sure if there is any better way?
# response = requests.post(self._urls.login(), json=data, headers=headers, timeout=self.timeout) # result = response.json() # if 'accessToken' in result : # self._access_token = result['accessToken'] # self._refresh_token = result['refreshToken'] # self._token_expire = result['tokenExpireTime'] # self._uuid = result['uuid'] # self._account_id = self.get_account_id() # if save_token: # self._save_token(result, token_path) self._access_token = 'xxxxxxxxxxxxxxx' self._refresh_token = 'xxxxxxxxxxxxxxxxxxxx' self._token_expire = '2026-02-14T13:35:35.780+0000' self._uuid = "xxxxxxxxxxxxxx" self._account_id = 'xxxxxxxxxxx' result = { "accessToken": self._access_token, "refreshToken": self._refresh_token, "tokenExpireTime":self._token_expire, "uuid": self._uuid, }by doing this, I can only get the account information, still can't place order. Anybody can advise?
unfortunately me too i've been trying all day to figure it out, i tried adding x-sv to the library but that didn't work either
access_token
Guys , let me clarify : this retry authentication is working perfectly. But you need to refresh/config your did/access_token correctly first , either retry or not . Dm me if you still have issue in authentication.
How often do we need to manually update the access token?
it is essentially using your web login session. when your PC web session expired or re-login , time to refresh.
access_token
Guys , let me clarify : this retry authentication is working perfectly. But you need to refresh/config your did/access_token correctly first , either retry or not . Dm me if you still have issue in authentication.
How often do we need to manually update the access token?
it is essentially using your web login session. when your PC web session expired or re-login , time to refresh.
Are you able to submit an order? I can only get account information, not able to place trades.