import os import sys import requests from dotenv import load_dotenv, set_key load_dotenv() sys.path.insert(0, os.path.dirname(__file__)) from utils.retry import RetryableHTTPError, raise_for_retryable_status, retry_with_backoff _RETRY = dict(max_retries=3, base_delay=1.0, max_delay=16.0, retryable_exceptions=(RetryableHTTPError,)) SHARD = "eu2" TOKEN_URL = f"https://api.{SHARD}.adobesign.com/oauth/v2/token" # initial auth code exchange REFRESH_URL = f"https://api.{SHARD}.adobesign.com/oauth/v2/refresh" # token refresh (non-standard separate endpoint) ENV_FILE = os.path.join(os.path.dirname(__file__), "..", ".env") def _refresh_access_token(): client_id = os.getenv("ADOBE_CLIENT_ID") client_secret = os.getenv("ADOBE_CLIENT_SECRET") refresh_token = os.getenv("ADOBE_REFRESH_TOKEN") if not all([client_id, client_secret, refresh_token]): raise RuntimeError("Missing credentials for token refresh. Run src/adobe_auth.py first.") data = { "grant_type": "refresh_token", "refresh_token": refresh_token, "client_id": client_id, "client_secret": client_secret, } resp = requests.post(REFRESH_URL, data=data) if not resp.ok: raise RuntimeError( f"Adobe Sign refresh token is invalid or expired ({resp.status_code}: {resp.text}). " "Run `python3 src/adobe_auth.py` to re-authenticate." ) new_token = resp.json()["access_token"] set_key(os.path.abspath(ENV_FILE), "ADOBE_ACCESS_TOKEN", new_token) os.environ["ADOBE_ACCESS_TOKEN"] = new_token return new_token @retry_with_backoff(**_RETRY) def adobe_api_post_multipart(endpoint, files, data=None): """Upload a file via multipart/form-data (e.g. transient documents).""" token = os.getenv("ADOBE_ACCESS_TOKEN") base_url = os.getenv("ADOBE_SIGN_BASE_URL", f"https://api.{SHARD}.adobesign.com/api/rest/v6") headers = {"Authorization": f"Bearer {token}"} url = f"{base_url}/{endpoint}" resp = requests.post(url, headers=headers, files=files, data=data or {}) if resp.status_code == 401: token = _refresh_access_token() headers["Authorization"] = f"Bearer {token}" resp = requests.post(url, headers=headers, files=files, data=data or {}) raise_for_retryable_status(resp) return resp.json() @retry_with_backoff(**_RETRY) def adobe_api_post_json(endpoint, body): """POST JSON body to an Adobe Sign endpoint.""" token = os.getenv("ADOBE_ACCESS_TOKEN") base_url = os.getenv("ADOBE_SIGN_BASE_URL", f"https://api.{SHARD}.adobesign.com/api/rest/v6") headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json", "Accept": "application/json", } url = f"{base_url}/{endpoint}" resp = requests.post(url, headers=headers, json=body) if resp.status_code == 401: token = _refresh_access_token() headers["Authorization"] = f"Bearer {token}" resp = requests.post(url, headers=headers, json=body) raise_for_retryable_status(resp) return resp.json() @retry_with_backoff(**_RETRY) def adobe_api_put_json(endpoint, body): """PUT JSON body to an Adobe Sign endpoint.""" token = os.getenv("ADOBE_ACCESS_TOKEN") base_url = os.getenv("ADOBE_SIGN_BASE_URL", f"https://api.{SHARD}.adobesign.com/api/rest/v6") headers = { "Authorization": f"Bearer {token}", "Content-Type": "application/json", "Accept": "application/json", } url = f"{base_url}/{endpoint}" resp = requests.put(url, headers=headers, json=body) if resp.status_code == 401: token = _refresh_access_token() headers["Authorization"] = f"Bearer {token}" resp = requests.put(url, headers=headers, json=body) raise_for_retryable_status(resp) return resp.json() @retry_with_backoff(**_RETRY) def adobe_api_get_bytes(endpoint): """Download binary content (e.g. PDF files) from the Adobe Sign API.""" token = os.getenv("ADOBE_ACCESS_TOKEN") base_url = os.getenv("ADOBE_SIGN_BASE_URL", f"https://api.{SHARD}.adobesign.com/api/rest/v6") headers = {"Authorization": f"Bearer {token}"} url = f"{base_url}/{endpoint}" resp = requests.get(url, headers=headers) if resp.status_code == 401: token = _refresh_access_token() headers["Authorization"] = f"Bearer {token}" resp = requests.get(url, headers=headers) raise_for_retryable_status(resp) return resp.content @retry_with_backoff(**_RETRY) def adobe_api_get(endpoint, params=None): token = os.getenv("ADOBE_ACCESS_TOKEN") base_url = os.getenv("ADOBE_SIGN_BASE_URL", f"https://api.{SHARD}.adobesign.com/api/rest/v6") headers = { "Authorization": f"Bearer {token}", "Accept": "application/json", } url = f"{base_url}/{endpoint}" resp = requests.get(url, headers=headers, params=params) if resp.status_code == 401: # Token expired — refresh and retry once token = _refresh_access_token() headers["Authorization"] = f"Bearer {token}" resp = requests.get(url, headers=headers, params=params) raise_for_retryable_status(resp) return resp.json() if __name__ == "__main__": library_docs = adobe_api_get("libraryDocuments") print("Library Documents:", library_docs)