#!/usr/bin/env python3 """ This Python code sample demonstrates the correct way to use your Bitnodes API key to perform an authenticated API request. Authenticated API request has a higher rate limit compared to the unauthenticated API request depending on the plan of your user account. Tested on Python 3.11.4. """ import hashlib import hmac import json import sys import time import urllib.error import urllib.request public_key = "_YOUR_API_PUBLIC_KEY_" # WARNING: KEEP private_key SECRET; NEVER INCLUDE PLAIN private_key IN REQUEST. private_key = "_YOUR_API_PRIVATE_KEY_" # See https://bitnodes.io/api/ for available API endpoints. # API endpoint being requested. uri = "https://bitnodes.io/api/v1/ping/" # Making the authenticated request. # Nonce must be the current UNIX epoch in microseconds. # 1 second has 1 million microseconds. # No more than 1 request (of same public key) can use the same nonce. # Make sure your system clock is in sync with Internet time-servers. # Bitnodes rejects nonce with a drift of over 60s from current time. nonce = str(int(time.time() * 1_000_000)) # Plaintext message. message = f"{public_key}:{nonce}:{uri}".encode() # Keyed-hash the plaintext message with HMAC-SHA256. sig = hmac.new(private_key.encode(), message, hashlib.sha256).hexdigest() # Authenticated request headers. headers = { "pubkey": public_key, # For identification. "nonce": nonce, # To prevent message replay. "sig": f"HMAC-SHA256:{sig}", # For authentication. } # Perform authenticated request. request = urllib.request.Request(uri, headers=headers) try: response = urllib.request.urlopen(request) except urllib.error.URLError as err: print(str(err)) sys.exit(1) # Preview sent request. print(f"Request URI: {uri}") print("Request headers:") print(json.dumps(dict(request.headers), indent=4)) # Note the RateLimit-Remaining response header in the HTTP 200 response. # On subsequent request after RateLimit-Remaining == 0, # you will see Retry-After response header in the HTTP 429 response # suggesting the amount of time in seconds before you can make a request again. print(f"Response status code: {response.status}") print("Response headers:") print(json.dumps(dict(response.headers), indent=4)) print("Response:") # On successful request, # this should print {'pong': True, 'username': 'YOUR_USERNAME'} print(json.loads(response.read().decode("utf-8"))) # If you get {'pong': True, 'username': ''}, # where the username is empty, it means your public key was missing from the # request headers. Check your request headers and retry the request.