hi @joeleveson we have our developer docs and a specific python sdk to use to help with API calls (the repo is private atm but it is available on pypi to pull and the references are included).
to get accounts you would do something like:
from frameio import Frameio
client = Frameio(
base_url="https://api.frame.io"
)
client.accounts.index()
Native Apps need to use PKCE for authorization so you would need to get a token using that method.
Here’s some pseudo code that might work for you for getting an auth token (FYI this is just what Claude Code spit out for me so YMMV):
import hashlib
import base64
import secrets
import urllib.parse
import webbrowser
from urllib.parse import urlparse, parse_qs
class AdobeIMSPKCEAuth:
def __init__(self, client_id, redirect_uri, scopes):
self.client_id = client_id
self.redirect_uri = redirect_uri
self.scopes = scopes
def generate_pkce_challenge(self):
# Generate code verifier (43-128 characters)
code_verifier = base64.urlsafe_b64encode(
secrets.token_bytes(32)
).decode('utf-8').rstrip('=')
# Generate code challenge (SHA256 hash of verifier)
code_challenge = base64.urlsafe_b64encode(
hashlib.sha256(code_verifier.encode()).digest()
).decode('utf-8').rstrip('=')
return code_verifier, code_challenge
def get_authorization_url(self, code_challenge, state):
base_url = "https://ims-na1.adobelogin.com/ims/authorize/v2"
params = {
"client_id": self.client_id,
"redirect_uri": self.redirect_uri,
"scope": " ".join(self.scopes),
"response_type": "code",
"code_challenge": code_challenge,
"code_challenge_method": "S256",
"state": state
}
return f"{base_url}?{urllib.parse.urlencode(params)}"
def exchange_code_for_token(self, authorization_code, code_verifier):
import requests
token_url = "https://ims-na1.adobelogin.com/ims/token/v3"
data = {
"grant_type": "authorization_code",
"client_id": self.client_id,
"code": authorization_code,
"redirect_uri": self.redirect_uri,
"code_verifier": code_verifier
}
headers = {
"Content-Type": "application/x-www-form-urlencoded"
}
response = requests.post(token_url, data=data, headers=headers)
if response.status_code == 200:
return response.json()
else:
raise Exception(f"Token exchange failed: {response.text}")
def authenticate(self):
# Step 1: Generate PKCE challenge
code_verifier, code_challenge = self.generate_pkce_challenge()
state = secrets.token_urlsafe(16) # CSRF protection
# Step 2: Build authorization URL
auth_url = self.get_authorization_url(code_challenge, state)
# Step 3: Open browser for user authorization
print("Opening browser for Adobe IMS authorization...")
print(f"Authorization URL: {auth_url}")
webbrowser.open(auth_url)
print("\nAfter authorization, you'll be redirected to your app's deep link.")
print("If your app isn't installed, you may see an error page with the authorization code in the URL.")
print("Look for 'code=' parameter in the URL or error message.")
authorization_code = input("Enter authorization code: ").strip()
if not authorization_code:
raise Exception("No authorization code provided")
# Step 4: Exchange authorization code for access token
print("Exchanging authorization code for access token...")
token_response = self.exchange_code_for_token(authorization_code, code_verifier)
return token_response
# Usage example:
def main():
# Configuration - Replace with your Adobe Developer Console credentials
CLIENT_ID = "your_client_id_from_adobe_console"
REDIRECT_URI = "your_redirect_uri_from_adobe_console" # e.g., "adobe+your_scheme://adobeid/your_client_id"
SCOPES = ["openid", "offline_access", "additional_info.roles", "email", "profile"]
# Initialize authenticator
auth = AdobeIMSPKCEAuth(CLIENT_ID, REDIRECT_URI, SCOPES)
try:
# Perform authentication flow
token_data = auth.authenticate()
# Extract tokens
access_token = token_data.get("access_token")
refresh_token = token_data.get("refresh_token")
expires_in = token_data.get("expires_in")
token_type = token_data.get("token_type")
print("\nAuthentication successful!")
print(f"Access Token: {access_token}")
print(f"Refresh Token: {refresh_token}")
print(f"Token Type: {token_type}")
print(f"Expires in: {expires_in} seconds")
# Use access_token for Adobe API calls:
# headers = {"Authorization": f"Bearer {access_token}"}
except Exception as e:
print(f"Authentication failed: {e}")
if __name__ == "__main__":
main()