Python SDK for the Universal Ads Third Party API
Project description
Universal Ads SDK
A Python SDK for interacting with the Universal Ads Third Party API. This SDK provides a simple and intuitive interface for managing campaigns, ad sets, ads, creatives, pixels, media uploads, custom audiences, and performance reports.
Features
- Creative Management: Create, read, update, and delete creatives
- Campaign, Ad Set, and Ad Management: List, create, get, and update campaign resources; async archive and unarchive with archive-job polling
- Pixel Access: List pixels, get pixel details, and retrieve pixel events
- Media Upload: Upload and verify media files
- Audience Management: Create and manage custom audiences for targeted advertising
- Reports: Access campaign, adset, and ad performance data
- Automatic Retries: Built-in retry logic for robust API interactions
- Type Hints: Full type annotation support for better development experience
Installation
pip install universal-ads-sdk
Quick Start
1. Initialize the Client
from universal_ads_sdk import UniversalAdsClient
# Initialize the client with your API credentials
client = UniversalAdsClient(
api_key="your-api-key",
private_key_pem="""-----BEGIN PRIVATE KEY-----
your-private-key-content
-----END PRIVATE KEY-----"""
)
2. Upload Media
# Upload a media file (using new API format)
upload_info = client.upload_media(
mime_type="image/jpeg",
adaccount_id="3d49e08c-465d-4673-a445-d4ba3575f032",
name="my-image.jpg"
)
# Use the presigned URL to upload your file
import requests
with open("/path/to/your/image.jpg", "rb") as f:
requests.put(upload_info["upload_url"], data=f)
# Verify the upload
media = client.verify_media(upload_info["id"])
print(f"Media verified: {media['status']}")
# Get media information
media_info = client.get_media(upload_info["id"])
print(f"Media filename: {media_info['filename']}")
3. Create a Creative
# Create a new creative
creative = client.create_creative(
adaccount_id="3d49e08c-465d-4673-a445-d4ba3575f032",
name="My Creative",
media_id="cc0f46c7-d9b9-4758-9479-17e1d77c5eea"
)
print(f"Created creative: {creative['id']}")
4. Create a Custom Audience
# Option 1: Create audience with uploaded media file
# First, upload a CSV or TXT file containing user identifiers (one per row)
upload_info = client.upload_media(
mime_type="text/csv",
adaccount_id="3d49e08c-465d-4673-a445-d4ba3575f032",
name="users.csv"
)
# Upload the file to the presigned URL
import requests
with open("/path/to/users.csv", "rb") as f:
requests.put(upload_info["upload_url"], data=f)
# Verify the upload
media = client.verify_media(upload_info["id"])
# Create a new custom audience using the uploaded media
audience = client.create_audience(
adaccount_id="3d49e08c-465d-4673-a445-d4ba3575f032",
name="My Custom Audience",
segment_type="email",
media_id=upload_info["id"],
description="An audience for targeted advertising"
)
print(f"Created audience: {audience['id']}")
# Option 2: Create audience with users list directly (max 10,000 users)
audience = client.create_audience(
adaccount_id="3d49e08c-465d-4673-a445-d4ba3575f032",
name="My Custom Audience",
segment_type="email",
users=["user@example.com", "another@example.com"],
description="An audience created with user list"
)
# Add or remove users from an existing audience
client.update_audience_users(
audience_id=audience["id"],
users=["user@example.com", "another@example.com"],
remove=False
)
5. Get Performance Reports
# Get campaign performance report
report = client.get_campaign_report(
adaccount_id="3d49e08c-465d-4673-a445-d4ba3575f032",
start_date="2024-01-01T00:00:00",
end_date="2024-01-31T23:59:59",
date_aggregation="DAY",
attribution_window="7_day"
)
print(f"Report contains {len(report['data'])} campaigns")
# Schedule an advanced report for asynchronous processing
scheduled_report = client.schedule_report(
start_date="2024-01-01T00:00:00",
end_date="2024-01-31T23:59:59",
entity_level="campaign",
adaccount_ids=["3d49e08c-465d-4673-a445-d4ba3575f032"],
dimensions=["state", "dma"],
time_aggregation="day"
)
print(f"Scheduled report ID: {scheduled_report['scheduled_report_id']}")
# Check scheduled report status
report_status = client.get_scheduled_report(scheduled_report['scheduled_report_id'])
print(f"Report status: {report_status['status']}")
6. Get Organizations and Ad Accounts
# Get all organizations
organizations = client.get_organizations(limit=50)
print(f"Found {len(organizations['data'])} organizations")
# Get all ad accounts
adaccounts = client.get_adaccounts(limit=50)
print(f"Found {len(adaccounts['data'])} ad accounts")
API Reference
Client Initialization
UniversalAdsClient(
api_key: str, # Your API key
private_key_pem: str, # Your private key in PEM format
base_url: Optional[str] = None, # API base URL (defaults to production)
timeout: int = 30, # Request timeout in seconds
max_retries: int = 3, # Maximum retry attempts
headers: Optional[Dict[str, str]] = None # Optional headers added to every request
)
Creative Management
Get All Creatives
creatives = client.get_creatives(
adaccount_id="account-id", # Optional: filter by account
campaign_id="campaign-id", # Optional: filter by campaign
adset_id="adset-id", # Optional: filter by adset
ad_id="ad-id", # Optional: filter by ad
limit=50, # Optional: limit results
offset=0, # Optional: pagination offset
sort="name_asc" # Optional: sort order
)
Get Specific Creative
creative = client.get_creative("creative-id")
Create Creative
creative = client.create_creative(
adaccount_id="account-id",
name="Creative Name",
media_id="media-id"
)
Update Creative
creative = client.update_creative(
"creative-id",
name="New Name"
)
Delete Creative
client.delete_creative("creative-id")
Media Management
Upload Media
# New API format
upload_info = client.upload_media(
mime_type="image/jpeg",
adaccount_id="account-id",
name="my-image.jpg"
)
Get Media
media = client.get_media("media-id")
Verify Media
media = client.verify_media("media-id")
Reporting
Campaign Report
report = client.get_campaign_report(
adaccount_id="account-id", # Required
start_date="2024-01-01T00:00:00", # Optional (YYYY-MM-DDTHH:MM:SS)
end_date="2024-01-31T23:59:59", # Optional (YYYY-MM-DDTHH:MM:SS)
campaign_ids=["id1", "id2"], # Optional
adset_ids=["id1", "id2"], # Optional
ad_ids=["id1", "id2"], # Optional
date_aggregation="DAY", # Optional: HOUR, DAY, LIFETIME, TOTAL
attribution_window="7_day", # Optional: 7_day, 14_day, 30_day
limit=100, # Optional
offset=0 # Optional
)
Adset Report
report = client.get_adset_report(
adaccount_id="account-id", # Required
start_date="2024-01-01T00:00:00", # Optional (YYYY-MM-DDTHH:MM:SS)
end_date="2024-01-31T23:59:59", # Optional (YYYY-MM-DDTHH:MM:SS)
campaign_ids=["id1", "id2"], # Optional
adset_ids=["id1", "id2"], # Optional
ad_ids=["id1", "id2"], # Optional
date_aggregation="DAY", # Optional: HOUR, DAY, LIFETIME, TOTAL
attribution_window="7_day", # Optional: 7_day, 14_day, 30_day
limit=100, # Optional
offset=0 # Optional
)
Ad Report
report = client.get_ad_report(
adaccount_id="account-id", # Required
start_date="2024-01-01T00:00:00", # Optional (YYYY-MM-DDTHH:MM:SS)
end_date="2024-01-31T23:59:59", # Optional (YYYY-MM-DDTHH:MM:SS)
campaign_ids=["id1", "id2"], # Optional
adset_ids=["id1", "id2"], # Optional
ad_ids=["id1", "id2"], # Optional
date_aggregation="DAY", # Optional: HOUR, DAY, LIFETIME, TOTAL
attribution_window="7_day", # Optional: 7_day, 14_day, 30_day
limit=100, # Optional
offset=0 # Optional
)
Schedule Report
scheduled_report = client.schedule_report(
start_date="2024-01-01T00:00:00",
end_date="2024-01-31T23:59:59",
entity_level="campaign", # campaign, adset, or ad
adaccount_ids=["account-id"],
campaign_ids=["id1", "id2"], # Optional
adset_ids=["id1", "id2"], # Optional
ad_ids=["id1", "id2"], # Optional
dimensions=["state", "dma"], # Optional: device_type, dma, state, zip_code
time_aggregation="day", # Optional: hour, day, or total
attribution_window="7_day", # Optional: 7_day, 14_day, 30_day
limit=50000 # Optional, default: 100000
)
Get Scheduled Report
report_status = client.get_scheduled_report("scheduled-report-id")
Campaign Management
Get All Campaigns
campaigns = client.get_campaigns(
adaccount_id="account-id", # Required
campaign_ids=["campaign-1"], # Optional: filter by campaign IDs
name="Spring Campaign", # Optional
status=["active", "paused"], # Optional: single string also accepted
campaign_type="performance", # Optional: performance, content_select
include_archived=False, # Optional
limit=50, # Optional
offset=0, # Optional
sort="id_asc" # Optional
)
Create / Update Campaign
campaign = client.create_campaign(
adaccount_id="account-id",
name="Spring Campaign",
objective="web_conversions"
)
updated = client.update_campaign(campaign["id"], name="Spring Campaign v2")
Async archive / unarchive (campaign, ad set, ad)
Archive and unarchive run asynchronously. Each start POST returns archive_job_id, polling_timeout_seconds, and entity_count. Poll with get_archive_job until status is completed, partially_failed, or failed, or use poll_archive_job with archive_start_response=start to apply the suggested timeout from the start response.
start = client.archive_campaign("campaign-uuid")
final = client.poll_archive_job(
start["archive_job_id"],
archive_start_response=start,
)
# Ad set and single-ad equivalents
client.unarchive_adset("adset-uuid")
client.archive_ad("ad-uuid")
# One-shot status (no wait)
job = client.get_archive_job("archive-job-uuid")
Ad Set Management
Get All Ad Sets
adsets = client.get_adsets(
adaccount_id="account-id", # Required
campaign_ids=["campaign-id"], # Optional
adset_ids=["adset-id"], # Optional
name="Adults 25-44", # Optional
status=["active", "paused"], # Optional
include_archived=False, # Optional
limit=50, # Optional
offset=0, # Optional
sort="id_asc" # Optional
)
Create / Update Ad Set
adset = client.create_adset(
adaccount_id="account-id",
campaign_id="campaign-id",
name="Adults 25-44"
)
updated = client.update_adset(adset["id"], name="Adults 25-54")
Ad Management
Get All Ads
ads = client.get_ads(
adaccount_id="account-id", # Required
campaign_ids=["campaign-id"], # Optional
adset_ids=["adset-id"], # Optional
ad_ids=["ad-id"], # Optional
status=["active", "paused"], # Optional
include_archived=False, # Optional
limit=50, # Optional
offset=0 # Optional
)
Create / Update Ad
ad = client.create_ad(
adaccount_id="account-id",
adset_id="adset-id",
creative_id="creative-id",
name="Homepage Hero Ad"
)
updated = client.update_ad(ad["id"], name="Homepage Hero Ad v2")
Pixel Endpoints
Get Pixels
pixels = client.get_pixels(
adaccount_id="account-id", # Required
limit=50, # Optional
offset=0 # Optional
)
pixel = client.get_pixel("pixel-id")
events = client.get_pixel_events("pixel-id", limit=100, offset=0)
Audience Management
Audience File Format Requirements
When creating or updating audiences with media_id, you need to upload a media file containing user data. The file must meet these requirements:
- File Format: CSV or TXT files only
- Structure: Single column format (one identifier per row)
- Encoding: UTF-8 encoding
- File Size: Maximum 25MB
- Content:
- For email audiences: Each row must contain a valid email address
- For other audience types: Each row contains a single identifier (e.g., IP address, Blockgraph ID, Experian LUID, Liveramp ID)
Example CSV file for email audiences:
user1@example.com
user2@example.com
user3@example.com
Example TXT file for email audiences:
user1@example.com
user2@example.com
user3@example.com
Upload Process:
- Upload your file using the
upload_media()method to get amedia_id - Use the
media_idwhen creating an audience or updating audience users - The file will be validated automatically
Get All Audiences
audiences = client.get_audiences(
adaccount_id="account-id", # Required
name="Audience Name", # Optional: filter by name
status="active", # Optional: filter by status
limit=50, # Optional: limit results
offset=0, # Optional: pagination offset
sort="name_asc" # Optional: sort order
)
Get Specific Audience
audience = client.get_audience("audience-id")
Create Audience
# Option 1: Create audience with media file
# Note: media_id must reference a CSV or TXT file uploaded via upload_media()
# The file must contain one identifier per row (see Audience File Format Requirements above)
audience = client.create_audience(
adaccount_id="account-id",
name="Audience Name",
segment_type="email", # email, ctv, ip_address, mobile_ad_id, etc.
media_id="media-id", # From upload_media() response
description="Optional description", # Optional
)
# Option 2: Create audience with users list (max 10,000 users)
audience = client.create_audience(
adaccount_id="account-id",
name="Audience Name",
segment_type="email",
users=["user1@example.com", "user2@example.com"],
description="Optional description" # Optional
)
Update Audience
audience = client.update_audience(
"audience-id",
name="Updated Audience Name",
description="Updated description"
)
Update Audience Users
# Add users to an audience
client.update_audience_users(
audience_id="audience-id",
users=["user1@example.com", "user2@example.com"],
remove=False # Set to True to remove users instead
)
# Remove users from an audience
client.update_audience_users(
audience_id="audience-id",
users=["user1@example.com"],
remove=True
)
# Update audience users using uploaded media
client.update_audience_users(
audience_id="audience-id",
media_id="new-media-id",
remove=False
)
Delete Audience
client.delete_audience("audience-id")
Me Endpoints
Get Organizations
organizations = client.get_organizations(
limit=50, # Optional: limit results (default: 10, max: 100)
offset=0 # Optional: pagination offset (default: 0)
)
Get Ad Accounts
adaccounts = client.get_adaccounts(
limit=50, # Optional: limit results (default: 10, max: 100)
offset=0, # Optional: pagination offset (default: 0)
organization_ids=["org-id-1", "org-id-2"], # Optional: repeatable organization_id query filters
authorization_statuses=["authorized"] # Optional: authorized, not_authorized
)
Error Handling
The SDK provides specific exception types for different error scenarios:
from universal_ads_sdk import UniversalAdsError, AuthenticationError, APIError
try:
creative = client.create_creative(...)
except AuthenticationError as e:
print(f"Authentication failed: {e}")
except APIError as e:
print(f"API error {e.status_code}: {e}")
print(f"Response data: {e.response_data}")
except UniversalAdsError as e:
print(f"SDK error: {e}")
Configuration
Environment Variables
You can also initialize the client using environment variables:
import os
from universal_ads_sdk import UniversalAdsClient
client = UniversalAdsClient(
api_key=os.getenv("UNIVERSAL_ADS_API_KEY"),
private_key_pem=os.getenv("UNIVERSAL_ADS_PRIVATE_KEY")
)
Custom Base URL
For testing or development, you can use a custom base URL:
client = UniversalAdsClient(
api_key="your-api-key",
private_key_pem="your-private-key",
base_url="https://staging-api.universalads.com/v1"
)
Authentication
The SDK uses request signing for secure API access. Each request is signed with your private key and includes:
Requirements
- Python 3.8+
- requests >= 2.25.0
- cryptography >= 3.4.0
- urllib3 >= 1.26.0
Security
API Credentials
- Never commit API credentials to version control
- Use environment variables for production deployments
- Test files with credentials are excluded from git via
.gitignore
Environment Variables (Recommended)
export UNIVERSAL_ADS_API_KEY="your-api-key"
export UNIVERSAL_ADS_PRIVATE_KEY="your-private-key-pem"
import os
from universal_ads_sdk import UniversalAdsClient
client = UniversalAdsClient(
api_key=os.getenv("UNIVERSAL_ADS_API_KEY"),
private_key_pem=os.getenv("UNIVERSAL_ADS_PRIVATE_KEY")
)
Development
Running Tests
The SDK includes test templates in the tests/ directory. For security, use environment variables:
# Set up environment variables
cp env.template .env
# Edit .env with your credentials
pip install python-dotenv # Optional, for better .env support
# Quick test (basic validation)
python tests/test_template.py
# Comprehensive test (all endpoints)
python tests/comprehensive_test.py
See tests/README.md for detailed testing information.
For development testing with pytest:
pip install -e ".[dev]"
pytest
Code Formatting
black universal_ads_sdk/
flake8 universal_ads_sdk/
Support
- Documentation: https://developers.universalads.com/
- Issues: GitHub Issues
- Email: support+sdk@universalads.com
License
This project is licensed under the MIT License - see the LICENSE file for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file universal_ads_sdk-2.2.0.tar.gz.
File metadata
- Download URL: universal_ads_sdk-2.2.0.tar.gz
- Upload date:
- Size: 29.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e6101cb4ba41d2b610851726d10c8741d167b8237af84c2cbaf7d028653a1b0a
|
|
| MD5 |
78593d68422e8ed9968e657b4d65f075
|
|
| BLAKE2b-256 |
4555c45b848cc5b5dc1bff2ba6505ed288478fdc97f7a7fb99232339df664be6
|
File details
Details for the file universal_ads_sdk-2.2.0-py3-none-any.whl.
File metadata
- Download URL: universal_ads_sdk-2.2.0-py3-none-any.whl
- Upload date:
- Size: 27.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.4
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
da5a1b77af49366da3a71b47a880a26ef73723e804299745fbf3a2f21b16b893
|
|
| MD5 |
0e1415ac19e7920bd2f47de3b4a150bc
|
|
| BLAKE2b-256 |
53e17c612d01bb12104b1b1e106ee807805d6f5f89ead7de998094dd54b3280f
|