import requests
import time
import hmac
import hashlib
import base64
import json
from urllib.parse import urlparse
class UnicyFalconApiClient:
def __init__(self, api_key: str, hmac_secret: str, base_url: str, timeout: int = 30):
self.api_key = api_key
self.hmac_secret = hmac_secret
self.base_url = base_url.rstrip('/')
self.timeout = timeout
self.session = requests.Session()
def _sign(self, method: str, uri: str, body: str, timestamp: int) -> str:
payload = f"{method.upper()}|{uri}|{body}|{timestamp}"
signature = hmac.new(
self.hmac_secret.encode('utf-8'),
payload.encode('utf-8'),
hashlib.sha256
).digest()
return base64.b64encode(signature).decode('utf-8')
def request(self, method: str, endpoint: str, data=None, params=None):
url = f"{self.base_url}/{endpoint.lstrip('/')}"
timestamp = int(time.time())
body = json.dumps(data) if data else ''
parsed_url = urlparse(self.base_url)
base_path = parsed_url.path or ''
uri = f"{base_path}/{endpoint.lstrip('/')}"
signature = self._sign(method, uri, body, timestamp)
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'X-API-Key': self.api_key,
'X-Timestamp': str(timestamp),
'X-Signature': signature,
}
response = self.session.request(
method=method.upper(),
url=url,
headers=headers,
json=data if data else None,
params=params,
timeout=self.timeout
)
payload = response.json()
if response.status_code >= 400:
message = payload.get('message', 'Unknown error')
raise Exception(f"API Error (HTTP {response.status_code}): {message}")
return payload
def get(self, endpoint: str, params=None):
return self.request('GET', endpoint, params=params)
def post(self, endpoint: str, data=None):
return self.request('POST', endpoint, data=data)
def put(self, endpoint: str, data=None):
return self.request('PUT', endpoint, data=data)
def delete(self, endpoint: str):
return self.request('DELETE', endpoint)