Skip to content

Latest commit

 

History

History
932 lines (724 loc) · 26.2 KB

File metadata and controls

932 lines (724 loc) · 26.2 KB

Stack0 Python SDK

The official Python SDK for Stack0 -- a modular platform for email, CDN, screenshots, AI extraction, integrations, and marketing automation.

  • Fully typed with Pydantic models and Literal types
  • Sync and async clients with identical APIs
  • Context manager support for automatic resource cleanup
  • Python 3.10+

Installation

pip install stack0

Quick Start

Synchronous

from stack0 import Stack0
from stack0.mail.types import SendEmailRequest

stack0 = Stack0(api_key="stack0_...")

# Send an email
response = stack0.mail.send(SendEmailRequest(
    from_="[email protected]",
    to="[email protected]",
    subject="Hello from Stack0",
    html="<h1>Welcome</h1><p>Thanks for signing up.</p>",
))
print(response.id, response.status)

stack0.close()

Async

import asyncio
from stack0 import AsyncStack0
from stack0.mail.types import SendEmailRequest

async def main():
    async with AsyncStack0(api_key="stack0_...") as stack0:
        response = await stack0.mail.send(SendEmailRequest(
            from_="[email protected]",
            to="[email protected]",
            subject="Hello from Stack0",
            html="<h1>Welcome</h1>",
        ))
        print(response.id)

asyncio.run(main())

Context Manager (Sync)

from stack0 import Stack0

with Stack0(api_key="stack0_...") as stack0:
    analytics = stack0.mail.get_analytics()
    print(f"Delivery rate: {analytics.delivery_rate}%")

Client Configuration

from stack0 import Stack0, AsyncStack0

client = Stack0(
    api_key="stack0_...",       # Required. Your Stack0 API key.
    base_url=None,              # Optional. Custom API base URL.
    cdn_url=None,               # Optional. CDN base URL for image transforms.
    timeout=30.0,               # Optional. Request timeout in seconds.
)

Both Stack0 and AsyncStack0 accept the same parameters.

Modules

Access each product through a property on the client:

Property Module Description
stack0.mail Mail Transactional email, campaigns, sequences, contacts
stack0.cdn CDN File uploads, image transforms, video processing
stack0.screenshots Screenshots Webpage screenshot capture
stack0.extraction Extraction AI-powered web content extraction
stack0.integrations Integrations Unified third-party API connections
stack0.marketing Marketing Trends, content, scripts, calendar

Mail

Send transactional emails, manage domains, templates, contacts, audiences, campaigns, sequences, and events.

Sending Email

from stack0.mail.types import SendEmailRequest, SendBatchEmailRequest, SendBroadcastEmailRequest

# Single email
response = stack0.mail.send(SendEmailRequest(
    from_="[email protected]",
    to="[email protected]",
    subject="Order Confirmed",
    html="<p>Your order #1234 has been confirmed.</p>",
    tags=["transactional", "orders"],
))

# Batch (up to 100 emails)
batch = stack0.mail.send_batch(SendBatchEmailRequest(
    emails=[
        SendEmailRequest(from_="[email protected]", to="[email protected]", subject="Hi A", html="<p>Hello A</p>"),
        SendEmailRequest(from_="[email protected]", to="[email protected]", subject="Hi B", html="<p>Hello B</p>"),
    ],
))

# Broadcast (same content, up to 1000 recipients)
broadcast = stack0.mail.send_broadcast(SendBroadcastEmailRequest(
    from_="[email protected]",
    to=["[email protected]", "[email protected]"],
    subject="Weekly Update",
    html="<p>Here is your weekly update.</p>",
))

Using Templates

response = stack0.mail.send(SendEmailRequest(
    from_="[email protected]",
    to="[email protected]",
    subject="Welcome",
    template_id="tmpl_abc123",
    template_variables={"name": "Alice", "plan": "Pro"},
))

Email Management

# Get email details
email = stack0.mail.get("email_id")

# List emails with filters
from stack0.mail.types import ListEmailsRequest
emails = stack0.mail.list(ListEmailsRequest(
    status="delivered",
    limit=50,
))

# Resend / cancel
stack0.mail.resend("email_id")
stack0.mail.cancel("email_id")

Analytics

from stack0.mail.types import TimeSeriesAnalyticsRequest

analytics = stack0.mail.get_analytics()
print(f"Sent: {analytics.sent}, Delivery rate: {analytics.delivery_rate}")

timeseries = stack0.mail.get_time_series_analytics(TimeSeriesAnalyticsRequest(days=30))
hourly = stack0.mail.get_hourly_analytics()
senders = stack0.mail.list_senders()

Domains (stack0.mail.domains)

from stack0.mail.types import ListDomainsRequest, AddDomainRequest

# List domains
domains = stack0.mail.domains.list(ListDomainsRequest(project_slug="my-project"))

# Add and verify a domain
result = stack0.mail.domains.add(AddDomainRequest(domain="mail.example.com"))
dns_records = stack0.mail.domains.get_dns_records("domain_id")
verification = stack0.mail.domains.verify("domain_id")

# Manage
stack0.mail.domains.set_default("domain_id")
stack0.mail.domains.delete("domain_id")

Templates (stack0.mail.templates)

from stack0.mail.types import CreateTemplateRequest, PreviewTemplateRequest

template = stack0.mail.templates.create(CreateTemplateRequest(
    name="Welcome Email",
    slug="welcome",
    subject="Welcome, {{name}}!",
    html="<h1>Welcome, {{name}}</h1>",
))

# List, get, get by slug
templates = stack0.mail.templates.list()
template = stack0.mail.templates.get("template_id")
template = stack0.mail.templates.get_by_slug("welcome")

# Preview with variables
preview = stack0.mail.templates.preview(PreviewTemplateRequest(
    id="template_id",
    variables={"name": "Alice"},
))

Contacts (stack0.mail.contacts)

from stack0.mail.types import CreateContactRequest, ImportContactsRequest, ImportContactInput

contact = stack0.mail.contacts.create(CreateContactRequest(
    email="[email protected]",
    first_name="Alice",
    last_name="Smith",
    metadata={"plan": "pro"},
))

# Bulk import
result = stack0.mail.contacts.import_contacts(ImportContactsRequest(
    contacts=[
        ImportContactInput(email="[email protected]", first_name="A"),
        ImportContactInput(email="[email protected]", first_name="B"),
    ],
    audience_id="aud_123",
))
print(f"Imported: {result.imported}, Skipped: {result.skipped}")

Audiences (stack0.mail.audiences)

from stack0.mail.types import CreateAudienceRequest, AddContactsToAudienceRequest

audience = stack0.mail.audiences.create(CreateAudienceRequest(
    name="Newsletter Subscribers",
    description="Users who opted in to the newsletter",
))

stack0.mail.audiences.add_contacts(AddContactsToAudienceRequest(
    id=audience.id,
    contact_ids=["contact_1", "contact_2"],
))

Campaigns (stack0.mail.campaigns)

from stack0.mail.types import CreateCampaignRequest, SendCampaignRequest

campaign = stack0.mail.campaigns.create(CreateCampaignRequest(
    name="Product Launch",
    subject="Introducing our new feature",
    from_email="[email protected]",
    html="<h1>Big news</h1>",
    audience_id="aud_123",
))

# Send immediately
result = stack0.mail.campaigns.send(SendCampaignRequest(
    id=campaign.id,
    send_now=True,
))

# Lifecycle
stack0.mail.campaigns.pause("campaign_id")
stack0.mail.campaigns.cancel("campaign_id")
stats = stack0.mail.campaigns.get_stats("campaign_id")

Sequences (stack0.mail.sequences)

Build visual email automation flows with triggers, delays, filters, branches, and A/B experiments.

from stack0.mail.types import (
    CreateSequenceRequest, CreateNodeRequest, CreateConnectionRequest,
    SetNodeEmailRequest, SetNodeTimerRequest,
)

# Create a sequence
sequence = stack0.mail.sequences.create(CreateSequenceRequest(
    name="Onboarding Flow",
    trigger_type="manual",
))

# Add nodes
email_node = stack0.mail.sequences.create_node(CreateNodeRequest(
    id=sequence.id,
    node_type="email",
    name="Welcome Email",
    position_x=0,
    position_y=100,
))

timer_node = stack0.mail.sequences.create_node(CreateNodeRequest(
    id=sequence.id,
    node_type="timer",
    name="Wait 1 Day",
    position_x=0,
    position_y=200,
))

# Configure nodes
stack0.mail.sequences.set_node_email(sequence.id, SetNodeEmailRequest(
    node_id=email_node.id,
    subject="Welcome!",
    html="<p>Thanks for joining.</p>",
))

stack0.mail.sequences.set_node_timer(sequence.id, SetNodeTimerRequest(
    node_id=timer_node.id,
    delay_amount=1,
    delay_unit="days",
))

# Connect nodes
stack0.mail.sequences.create_connection(CreateConnectionRequest(
    id=sequence.id,
    source_node_id=email_node.id,
    target_node_id=timer_node.id,
))

# Publish
stack0.mail.sequences.publish(sequence.id)

Events (stack0.mail.events)

from stack0.mail.types import CreateEventRequest, TrackEventRequest

event = stack0.mail.events.create(CreateEventRequest(
    name="user.signed_up",
    description="Fired when a user completes registration",
))

stack0.mail.events.track(TrackEventRequest(
    event_name="user.signed_up",
    contact_email="[email protected]",
    properties={"plan": "pro", "source": "landing_page"},
))

Mail Method Reference

Sub-client Methods
mail send, send_batch, send_broadcast, get, list, resend, cancel, get_analytics, get_time_series_analytics, get_hourly_analytics, list_senders
mail.domains list, add, get_dns_records, verify, delete, set_default
mail.templates list, get, get_by_slug, create, update, delete, preview
mail.audiences list, get, create, update, delete, list_contacts, add_contacts, remove_contacts
mail.contacts list, get, create, update, delete, import_contacts
mail.campaigns list, get, create, update, delete, send, pause, cancel, duplicate, get_stats
mail.sequences list, get, create, update, delete, publish, pause, resume, archive, duplicate, create_node, update_node, delete_node, set_node_email, set_node_timer, set_node_filter, set_node_branch, set_node_experiment, create_connection, delete_connection, list_entries, add_contact, remove_contact, get_analytics
mail.events list, get, create, update, delete, track, track_batch, list_occurrences, get_analytics

CDN

Upload, manage, and transform files. Includes video transcoding, GIF generation, private file storage, download bundles, and S3 imports.

Upload Files

# Simple upload (handles presigned URL flow automatically)
with open("photo.jpg", "rb") as f:
    asset = stack0.cdn.upload(
        project_slug="my-project",
        file=f.read(),
        filename="photo.jpg",
        mime_type="image/jpeg",
        folder="uploads/photos",
    )
print(asset.url)

Async Upload

async with AsyncStack0(api_key="stack0_...") as stack0:
    with open("photo.jpg", "rb") as f:
        asset = await stack0.cdn.upload(
            project_slug="my-project",
            file=f.read(),
            filename="photo.jpg",
            mime_type="image/jpeg",
        )

Image Transforms

Generate transformed image URLs client-side (no API call required).

from stack0.cdn.types import TransformOptions

url = stack0.cdn.get_transform_url(
    "https://cdn.example.com/assets/photo.jpg",
    TransformOptions(
        width=800,
        height=600,
        format="webp",
        quality=85,
    ),
)
# https://cdn.example.com/assets/photo.jpg?w=828&h=600&f=webp&q=85

Supported transform options: width, height, format, quality, fit, crop, blur, sharpen, brightness, saturation, grayscale, rotate, flip, flop.

Asset Management

from stack0.cdn.types import ListAssetsRequest, MoveAssetsRequest

# List assets
assets = stack0.cdn.list(ListAssetsRequest(
    project_slug="my-project",
    type="image",
    search="photo",
))

# Get, update, delete
asset = stack0.cdn.get("asset_id")
stack0.cdn.delete("asset_id")
stack0.cdn.delete_many(["asset_1", "asset_2"])

# Move assets between folders
stack0.cdn.move(MoveAssetsRequest(
    asset_ids=["asset_1", "asset_2"],
    target_folder="archive/2024",
))

Folders

from stack0.cdn.types import CreateFolderRequest, GetFolderTreeRequest

tree = stack0.cdn.get_folder_tree(GetFolderTreeRequest(project_slug="my-project"))
folder = stack0.cdn.create_folder(CreateFolderRequest(
    project_slug="my-project",
    name="photos",
    parent_id=None,
))
stack0.cdn.get_folder("folder_id")
stack0.cdn.get_folder_by_path("uploads/photos")
stack0.cdn.delete_folder("folder_id", delete_contents=True)

Video

from stack0.cdn.types import TranscodeVideoRequest, GenerateGifRequest

# Transcode
job = stack0.cdn.transcode(TranscodeVideoRequest(
    asset_id="video_asset_id",
    project_slug="my-project",
))

# Check status
job = stack0.cdn.get_job(job.id)

# Get streaming URLs (HLS/DASH)
urls = stack0.cdn.get_streaming_urls("video_asset_id")

# Generate GIF from video segment
gif = stack0.cdn.generate_gif(GenerateGifRequest(
    asset_id="video_asset_id",
    project_slug="my-project",
    start_time=5.0,
    end_time=10.0,
    width=320,
))

Private Files

# Upload private file
private_file = stack0.cdn.upload_private(
    project_slug="my-project",
    file=file_bytes,
    filename="contract.pdf",
    mime_type="application/pdf",
    description="Q4 contract",
)

# Generate time-limited download URL
from stack0.cdn.types import PrivateDownloadUrlRequest
download = stack0.cdn.get_private_download_url(PrivateDownloadUrlRequest(
    file_id=private_file.id,
    expires_in=3600,  # seconds
))
print(download.download_url)

CDN Method Reference

Category Methods
Upload get_upload_url, confirm_upload, upload
Assets get, list, update, delete, delete_many, move
Transforms get_transform_url
Folders get_folder_tree, create_folder, get_folder, get_folder_by_path, update_folder, list_folders, move_folder, delete_folder
Video transcode, get_job, list_jobs, cancel_job, get_streaming_urls, get_thumbnail, regenerate_thumbnail, extract_audio, list_thumbnails
GIFs generate_gif, get_gif, list_gifs
Merge create_merge_job, get_merge_job, list_merge_jobs, cancel_merge_job
Private Files get_private_upload_url, confirm_private_upload, upload_private, get_private_download_url, get_private_file, update_private_file, delete_private_file, delete_private_files, list_private_files, move_private_files
Bundles create_bundle, get_bundle, list_bundles, get_bundle_download_url, delete_bundle
S3 Import create_import, get_import, list_imports, cancel_import, retry_import, list_import_files
Usage get_usage, get_usage_history, get_storage_breakdown

Screenshots

Capture high-quality screenshots of any webpage. Supports full-page capture, device emulation, custom viewports, batch processing, and scheduled captures.

Capture a Screenshot

from stack0.screenshots.types import CreateScreenshotRequest, GetScreenshotRequest

# Fire and forget
response = stack0.screenshots.capture(CreateScreenshotRequest(
    url="https://example.com",
    format="png",
    full_page=True,
    device_type="desktop",
))

# Capture and wait for result (polls until complete)
screenshot = stack0.screenshots.capture_and_wait(
    CreateScreenshotRequest(
        url="https://example.com",
        format="webp",
        full_page=True,
    ),
    poll_interval=1.0,   # seconds between polls
    timeout=60.0,        # max wait time
)
print(screenshot.image_url)

Async Capture

async with AsyncStack0(api_key="stack0_...") as stack0:
    screenshot = await stack0.screenshots.capture_and_wait(
        CreateScreenshotRequest(
            url="https://example.com",
            format="png",
            full_page=True,
        ),
    )

Batch Screenshots

from stack0.screenshots.types import CreateBatchScreenshotsRequest

# Process multiple URLs at once
job = stack0.screenshots.batch_and_wait(
    CreateBatchScreenshotsRequest(
        urls=["https://example.com", "https://example.org"],
        format="png",
        full_page=True,
    ),
    poll_interval=2.0,
    timeout=300.0,
)

Scheduled Captures

from stack0.screenshots.types import CreateScreenshotScheduleRequest

schedule = stack0.screenshots.create_schedule(CreateScreenshotScheduleRequest(
    url="https://example.com",
    frequency="daily",
    format="png",
    full_page=True,
))

# Manage schedules
stack0.screenshots.toggle_schedule(GetScheduleRequest(id=schedule.id))

Screenshots Method Reference

Category Methods
Capture capture, capture_and_wait, get, list, delete
Batch batch, batch_and_wait, get_batch_job, list_batch_jobs, cancel_batch_job
Schedules create_schedule, update_schedule, get_schedule, list_schedules, delete_schedule, toggle_schedule

Extraction

Extract structured data from any webpage using AI. Supports markdown conversion, schema-based extraction, and raw HTML retrieval.

Extraction Modes

Mode Description
markdown Convert page content to clean Markdown
schema Extract structured data matching a JSON schema
auto Let the AI decide the best extraction strategy
raw Return the raw HTML content

Extract Content

from stack0.extraction.types import CreateExtractionRequest

# Markdown extraction
result = stack0.extraction.extract_and_wait(
    CreateExtractionRequest(
        url="https://example.com/blog/post",
        mode="markdown",
    ),
)
print(result.markdown)

# Schema-based extraction
result = stack0.extraction.extract_and_wait(
    CreateExtractionRequest(
        url="https://example.com/product",
        mode="schema",
        schema_={"name": "string", "price": "number", "in_stock": "boolean"},
        prompt="Extract the main product details",
    ),
)
print(result.extracted_data)

Async Extraction

async with AsyncStack0(api_key="stack0_...") as stack0:
    result = await stack0.extraction.extract_and_wait(
        CreateExtractionRequest(
            url="https://example.com/article",
            mode="markdown",
            include_metadata=True,
        ),
    )
    print(result.page_metadata)

Batch Extraction

from stack0.extraction.types import CreateBatchExtractionsRequest

job = stack0.extraction.batch_and_wait(
    CreateBatchExtractionsRequest(
        urls=["https://example.com/page1", "https://example.com/page2"],
        mode="markdown",
    ),
)

Usage Tracking

usage = stack0.extraction.get_usage()
daily = stack0.extraction.get_usage_daily()

Extraction Method Reference

Category Methods
Extract extract, extract_and_wait, get, list, delete
Batch batch, batch_and_wait, get_batch_job, list_batch_jobs, cancel_batch_job
Schedules create_schedule, update_schedule, get_schedule, list_schedules, delete_schedule, toggle_schedule
Usage get_usage, get_usage_daily

Integrations

Connect to third-party services through a unified API. Manage OAuth connections and interact with CRM, storage, communication, and productivity tools.

Managing Connections

from stack0.integrations.types import InitiateOAuthRequest

# List existing connections
connections = stack0.integrations.list_connections()

# Start OAuth flow
oauth = stack0.integrations.initiate_oauth(InitiateOAuthRequest(
    connector_id="salesforce",
    redirect_url="https://app.example.com/callback",
))
print(oauth.authorization_url)

# Get connection details
connection = stack0.integrations.get_connection("conn_123")

# Delete a connection
stack0.integrations.delete_connection("conn_123")

CRM (stack0.integrations.crm)

from stack0.integrations.types import CreateContactInput

# Contacts
contacts = stack0.integrations.crm.list_contacts("conn_123")
contact = stack0.integrations.crm.create_contact("conn_123", CreateContactInput(
    email="[email protected]",
    first_name="Alice",
))

# Companies and Deals
companies = stack0.integrations.crm.list_companies("conn_123")
deals = stack0.integrations.crm.list_deals("conn_123")

Storage (stack0.integrations.storage)

files = stack0.integrations.storage.list_files("conn_123")
folders = stack0.integrations.storage.list_folders("conn_123")

Communication (stack0.integrations.communication)

from stack0.integrations.types import SendMessageInput

channels = stack0.integrations.communication.list_channels("conn_123")
stack0.integrations.communication.send_message("conn_123", SendMessageInput(
    channel_id="channel_123",
    content="Hello from Stack0!",
))

Productivity (stack0.integrations.productivity)

documents = stack0.integrations.productivity.list_documents("conn_123")
tables = stack0.integrations.productivity.list_tables("conn_123")

Integrations Method Reference

Sub-client Methods
integrations list_connections, get_connection, initiate_oauth, complete_oauth, update_connection, delete_connection, reconnect_connection, get_stats, list_logs, passthrough
integrations.crm list_contacts, get_contact, create_contact, update_contact, delete_contact, list_companies, get_company, create_company, update_company, delete_company, list_deals, get_deal, create_deal, update_deal, delete_deal
integrations.storage list_files, get_file, upload_file, delete_file, download_file, list_folders, create_folder, delete_folder
integrations.communication list_channels, send_message, list_messages, list_users
integrations.productivity list_documents, get_document, create_document, update_document, delete_document, list_tables, get_table, list_table_rows, get_table_row, create_table_row, update_table_row, delete_table_row

Marketing

Discover trends, generate content opportunities, manage scripts, schedule publications, and track analytics.

Trends

from stack0.marketing.types import DiscoverTrendsRequest

result = stack0.marketing.discover_trends(DiscoverTrendsRequest(
    project_slug="my-project",
    environment="production",
))

Content

from stack0.marketing.types import CreateContentRequest

content = stack0.marketing.create_content(CreateContentRequest(
    project_slug="my-project",
    title="10 Tips for Better Email Deliverability",
    body="...",
    content_type="blog_post",
))

# Approval workflow
stack0.marketing.approve_content(ApproveContentRequest(id=content.id))

Scripts and Calendar

from stack0.marketing.types import CreateScriptRequest, ScheduleContentRequest

script = stack0.marketing.create_script(CreateScriptRequest(
    project_slug="my-project",
    name="Product Demo Script",
    content="...",
))

stack0.marketing.schedule_content(ScheduleContentRequest(
    content_id=content.id,
    scheduled_at="2025-03-01T09:00:00Z",
    channel="blog",
))

Marketing Method Reference

Category Methods
Trends discover_trends, list_trends, get_trend, update_trend_status
Opportunities generate_opportunities, list_opportunities, get_opportunity, dismiss_opportunity
Content create_content, list_content, get_content, update_content, approve_content, reject_content, delete_content
Scripts create_script, list_scripts, get_script, update_script, create_script_version, get_script_versions, delete_script
Analytics get_analytics_overview, get_content_performance, get_trend_analytics, get_opportunity_conversion
Calendar schedule_content, list_calendar_entries, update_calendar_entry, cancel_calendar_entry, mark_content_published
Assets create_asset_job, list_asset_jobs, get_asset_job, update_asset_job_status, retry_asset_job, cancel_asset_job
Settings get_settings, update_settings, get_current_usage, get_usage_history, get_total_usage

Error Handling

All SDK errors inherit from Stack0Error. API errors include HTTP status codes, error codes, and the raw response body.

Exception Hierarchy

Stack0Error (base)
  APIError (status_code, code, response)
    AuthenticationError  (401)
    PermissionError      (403)
    NotFoundError        (404)
    RateLimitError       (429, retry_after)
    ValidationError      (400)
  TimeoutError
  NetworkError

Handling Errors

from stack0._exceptions import (
    Stack0Error,
    APIError,
    AuthenticationError,
    RateLimitError,
    NotFoundError,
    ValidationError,
    TimeoutError,
    NetworkError,
)

try:
    stack0.mail.send(request)
except AuthenticationError:
    print("Invalid API key")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after} seconds")
except NotFoundError:
    print("Resource not found")
except ValidationError as e:
    print(f"Invalid request: {e.message}")
except APIError as e:
    print(f"API error {e.status_code}: {e.message}")
    if e.code:
        print(f"Error code: {e.code}")
except TimeoutError:
    print("Request timed out")
except NetworkError:
    print("Network connectivity issue")
except Stack0Error as e:
    print(f"SDK error: {e}")

Shared Types

These types are used across multiple modules.

from stack0._types import Environment, BatchJobStatus, ScheduleFrequency

# Environment
env: Environment = "sandbox"       # or "production"

# BatchJobStatus
status: BatchJobStatus = "pending"  # "pending" | "processing" | "completed" | "failed" | "cancelled"

# ScheduleFrequency
freq: ScheduleFrequency = "daily"   # "hourly" | "daily" | "weekly" | "monthly"

Requirements

Documentation

For the full API reference, guides, and examples, visit stack0.dev/docs.

License

MIT