Page 1 of 1

HTTP 401 on basic REST call

Posted: Sun May 31, 2026 2:07 pm
by FoxySocks
I'm guessing I must be doing something wrong, but this snippet consistently returns a HTTP 401 for me. And does not return any device info. Also tried with v1 and v2 paths, same results. Can someone shed some light on this pls?

Code: Select all

import hashlib
import json
import time
import urllib.request
import urllib.error

API_KEY = "<YOUR-FOXESS-OPENAPI-KEY>"   # <-- paste your key here
DOMAIN  = "https://www.foxesscloud.com"
PATH    = "/op/v0/device/list"
UA      = ("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
           "(KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")

timestamp = str(round(time.time() * 1000))
# signature = md5( path + "\r\n" + token + "\r\n" + timestamp ), per the OpenAPI doc.
# The doc's Python example uses a RAW f-string (fr"..."), so \r\n are the literal
# characters backslash-r-backslash-n. (Using real CRLF gives the identical 401.)
signature = hashlib.md5(
    f"{PATH}\\r\\n{API_KEY}\\r\\n{timestamp}".encode("utf-8")
).hexdigest()

headers = {
    "Token": API_KEY,
    "Timestamp": timestamp,
    "Signature": signature,
    "Lang": "en",
    "Timezone": "Europe/London",
    "Content-Type": "application/json",
    "User-Agent": UA,
}
body = json.dumps({"currentPage": 1, "pageSize": 10}).encode("utf-8")
req = urllib.request.Request(DOMAIN + PATH, data=body, method="POST", headers=headers)

try:
    with urllib.request.urlopen(req, timeout=30) as resp:
        status, resp_headers, text = resp.status, dict(resp.headers), resp.read().decode()
except urllib.error.HTTPError as e:
    status, resp_headers, text = e.code, dict(e.headers), e.read().decode()

print("HTTP status:", status)
print("Response headers:")
for k, v in resp_headers.items():
    print(f"  {k}: {v}")
print("Body:", repr(text) if text else "<empty>")