Skip to main content

Documentation Index

Fetch the complete documentation index at: https://agentref.co/docs/llms.txt

Use this file to discover all available pages before exploring further.

The agentref Python package provides both synchronous and asynchronous clients for the AgentRef REST API v1. It uses httpx under the hood and returns Pydantic models for core resources. Some flexible surfaces, including Marketing Resources and parts of the affiliate workspace, return dictionaries or lists of dictionaries because their response shape can vary by resource kind.

Installation

pip install agentref

Quick Start

from agentref import AgentRef

client = AgentRef(api_key="ak_live_your_api_key_here")

# List all programs
result = client.programs.list()
print(f"Found {result.meta.total} programs")

# Get conversion stats
stats = client.conversions.stats(period="30d")
print(f"Revenue: ${stats.total_revenue / 100}")

Async Usage

from agentref import AsyncAgentRef

async with AsyncAgentRef(api_key="ak_live_...") as client:
    result = await client.programs.list()
    for program in result.data:
        print(program.name)

Configuration

client = AgentRef(
    api_key="ak_live_...",                        # or set AGENTREF_API_KEY env var
    base_url="https://www.agentref.co/api/v1",    # default
    timeout=30.0,                                  # 30s default
    max_retries=2,                                 # retries for GET + idempotent POST
)
ParameterTypeDefaultDescription
api_keystrAGENTREF_API_KEY envYour API key. Required.
base_urlstrhttps://www.agentref.co/api/v1API base URL
timeoutfloat30.0Request timeout in seconds
max_retriesint2Max retries for safe/idempotent requests

Resource Namespaces

The client exposes the full REST API v1 surface through resource namespaces:
NamespaceDescription
client.programsCreate, update, delete, and list affiliate programs
client.applicationsReview pending affiliate applications before they become memberships
client.affiliatesList approved memberships, block, and unblock affiliates
client.affiliate_workspaceAffiliate self-serve overview, programs, links, earnings, payouts, and clicks
client.marketing_resourcesMerchant and affiliate Marketing Resources workflows
client.conversionsList conversions, get stats, and fetch recent activity
client.payoutsList payouts, pending affiliates, stats, and create payouts
client.flagsList fraud flags, get stats, and resolve flags
client.billingCheck billing status, list tiers, and subscribe
client.merchantGet and update merchant profile
client.notificationsGet and update notification preferences
client.payout_infoGet and update payout payment details
client.onboardingComplete onboarding setup calls
client.trackingRead program tracking health
client.invitesInspect and claim public invite links
client.marketplaceDiscover marketplace programs and apply as an affiliate
client.webhooksCreate, list, update, delete webhook endpoints and rotate secrets

Programs

# List programs (paginated)
result = client.programs.list(status="active", limit=10, page=1)

# Auto-paginate through all programs
for program in client.programs.list_all():
    print(program.name)

# Async auto-pagination
async for program in client.programs.list_all():
    print(program.name)

# Get program details (includes readiness status)
detail = client.programs.get("prog-uuid")
print(detail.readiness)  # 'setup' | 'partial' | 'ready'

# Create a program
program = client.programs.create(
    name="Acme Referrals",
    commission_type="recurring",
    commission_percent=25,
    cookie_duration=60,
    currency="USD",
    idempotency_key="create-acme-v1",
)

# Update a program
client.programs.update("prog-uuid", commission_percent=30, status="active")

# Delete a program
client.programs.delete("prog-uuid")

# Get program stats
stats = client.programs.stats("prog-uuid", period="30d")

# List program affiliates
affiliates = client.programs.list_affiliates("prog-uuid", include_blocked=False)

# Manage invites
invite = client.programs.create_invite(
    "prog-uuid",
    email="partner@example.com",
    expires_in_days=7,
    idempotency_key="invite-partner-v1",
)
invites = client.programs.list_invites("prog-uuid")

# Manage coupons
coupon = client.programs.create_coupon(
    "prog-uuid",
    affiliate_id="aff-uuid",
    code="PARTNER20",
    idempotency_key="coupon-partner20",
)
coupons = client.programs.list_coupons("prog-uuid")
client.programs.delete_coupon("coupon-uuid")

# Marketplace settings
client.programs.update_marketplace(
    "prog-uuid",
    status="public",
    category="SaaS",
    description="Earn 25% recurring for every referral.",
)

# Stripe connection
stripe = client.programs.connect_stripe("prog-uuid")
print(stripe.auth_url)  # redirect merchant to complete OAuth
client.programs.disconnect_stripe("prog-uuid")

Applications

# Pending joins live in the Applications lifecycle
pending = client.applications.list(
    program_id="prog-uuid",
    status="pending",
)

client.applications.approve(
    pending.data[0].id,
    note="Relevant SaaS audience.",
    idempotency_key="approve-app-123",
)

client.applications.decline(
    "app-uuid",
    note="Audience is not a fit.",
)

Affiliates

# List approved or blocked affiliate memberships
result = client.affiliates.list(
    program_id="prog-uuid",
    status="approved",
    search="john",
    sort_by="totalRevenue",
    sort_order="desc",
    limit=25,
)

# Get single affiliate (with optional stats)
affiliate = client.affiliates.get("aff-uuid", include="stats")

# Block with reason
client.affiliates.block(
    "aff-uuid",
    reason="Suspicious click patterns detected",
    idempotency_key="block-aff-123",
)

# Unblock
client.affiliates.unblock("aff-uuid", idempotency_key="unblock-aff-123")

Affiliate Workspace

identity = client.affiliate_workspace.identity()
overview = client.affiliate_workspace.overview()
programs = client.affiliate_workspace.list_programs()

link = client.affiliate_workspace.create_link(
    name="Pricing",
    destination_path="/pricing",
    custom_slug="jane-review",
    program_id=programs[0].program_id,
    idempotency_key="create-pricing-link",
)

links = client.affiliate_workspace.list_links(program_id=programs[0].program_id)

client.affiliate_workspace.update_link(
    link["id"],
    name="Pricing - updated",
    target_url="https://merchant-site.com/pricing",
    is_active=True,
    program_id=programs[0].program_id,
)

client.affiliate_workspace.delete_link(
    "old-link-uuid",
    program_id=programs[0].program_id,
)

earnings = client.affiliate_workspace.earnings()
program_earnings = client.affiliate_workspace.list_program_earnings(
    programs[0].program_id,
    period="30d",
)
payouts = client.affiliate_workspace.list_payouts(
    program_id=programs[0].program_id,
)
clicks = client.affiliate_workspace.click_stats(
    program_id=programs[0].program_id,
    start_date="2026-05-01",
)
create_link uses destination_path and custom_slug. The current update API accepts name, target_url, and is_active; create a new link when you need a different destination path or custom slug.

Marketing Resources

# Merchant workflow
post = client.marketing_resources.create_social_post(
    "prog-uuid",
    title="Launch copy",
    body="Try AgentRef: {{affiliate_link}}",
    platforms=["linkedin"],
    status="published",
    idempotency_key="mr-launch-copy",
)

client.marketing_resources.publish(
    post["id"],
    program_id="prog-uuid",
    notify_affiliates=True,
    idempotency_key="publish-mr-launch-copy",
)

client.marketing_resources.update_social_post(
    post["id"],
    program_id="prog-uuid",
    title="Launch copy v2",
)

upload = client.marketing_resources.create_social_post_media_upload_session(
    post["id"],
    program_id="prog-uuid",
    file_name="launch.png",
    mime_type="image/png",
    file_size_bytes=125_000,
    idempotency_key="launch-media-upload",
)

# Upload the file bytes to upload["signed_url"], then attach the uploaded media.
client.marketing_resources.complete_social_post_media_upload(
    post["id"],
    program_id="prog-uuid",
    upload_path=upload["upload_path"],
    upload_token=upload["upload_token"],
    file_name="launch.png",
    alt_text="Launch product screenshot",
    idempotency_key="launch-media-complete",
)

client.marketing_resources.create_download_url(
    program_id="prog-uuid",
    resource_id=post["id"],
    idempotency_key="download-launch-copy",
)

# Affiliate workflow
resources = client.marketing_resources.list_for_affiliate(
    "prog-uuid",
    kind="social_posts",
)

resource = client.marketing_resources.get_for_affiliate(
    resources[0]["id"],
    program_id="prog-uuid",
)

rendered = client.marketing_resources.render_social_post(
    resources[0]["id"],
    program_id="prog-uuid",
    affiliate_link_id=link["id"],
)

download = client.marketing_resources.create_affiliate_download_url(
    program_id="prog-uuid",
    resource_id=resource["id"],
)
REST/SDK Marketing Resources support social posts, social-post media, publish/unpublish/archive/notify actions, and download URLs. Collection creation, external-link creation, generic file upload sessions, and URL import are currently available through Merchant MCP, not through the REST SDK.
MethodSurface
list, create_social_post, update_social_postMerchant REST/SDK
create_social_post_media_upload_session, complete_social_post_media_upload, replace_social_post_mediaMerchant REST/SDK
reorder_social_post_media, update_social_post_media, remove_social_post_mediaMerchant REST/SDK
publish, unpublish, archive, notify_affiliates, create_download_urlMerchant REST/SDK
list_for_affiliate, get_for_affiliate, render_social_post, create_affiliate_download_urlAffiliate REST/SDK
Collections, external links, generic file upload, URL importMerchant MCP only

Conversions

# List conversions with filters
result = client.conversions.list(
    program_id="prog-uuid",
    status="pending",
    start_date="2026-01-01",
    end_date="2026-03-23",
    limit=50,
)

# Aggregate stats
stats = client.conversions.stats(program_id="prog-uuid", period="30d")
print(f"{stats.total} conversions, ${stats.total_revenue / 100} revenue")

# Recent conversions
recent = client.conversions.recent(limit=5)

Payouts

# List completed payouts
result = client.payouts.list(status="completed", start_date="2026-01-01")

# List pending affiliates (ready for payout)
pending = client.payouts.list_pending(program_id="prog-uuid")

for aff in pending.data:
    print(f"{aff.name}: ${aff.pending_amount / 100} ({aff.currency})")

# Payout stats
payout_stats = client.payouts.stats(period="30d")

# Create a payout
payout = client.payouts.create(
    affiliate_id="aff-uuid",
    program_id="prog-uuid",
    method="paypal",
    notes="March payout",
    idempotency_key="payout-march-aff123",
)

Fraud Flags

# List open flags
result = client.flags.list(status="open", limit=20)

# Get flag stats
flag_stats = client.flags.stats()
print(f"{flag_stats.open} open flags")

# Resolve a flag
client.flags.resolve(
    "flag-uuid",
    status="dismissed",
    note="Verified legitimate traffic",
    block_affiliate=False,
    idempotency_key="resolve-flag-abc",
)

Billing

# Check current billing status
billing = client.billing.current()
print(f"Tier: {billing.tier}, Revenue: ${billing.monthly_revenue / 100}")

# List available tiers
tiers = client.billing.tiers()

# Subscribe to a tier
client.billing.subscribe(tier="growth", idempotency_key="subscribe-growth-v1")

Merchant

# Get merchant profile
merchant = client.merchant.get()

# Update merchant settings
client.merchant.update(
    company_name="Acme Inc.",
    timezone="America/New_York",
    default_cookie_duration=60,
)

Notifications

# Get notification preferences
prefs = client.notifications.get()

# Update preferences
client.notifications.update(
    new_affiliate=True,
    new_conversion=True,
    weekly_digest=True,
)

Payout Info

# Get payout info
info = client.payout_info.get()

# Update payout info
client.payout_info.update(
    payout_method="paypal",
    paypal_email="payments@acme.com",
)

Onboarding, Tracking, Invites, and Marketplace

client.onboarding.upsert_merchant_profile(company_name="Acme Inc.")
client.onboarding.complete()

tracking = client.tracking.get_program_status("prog-uuid")

invite = client.invites.get("invite-token")
claimed = client.invites.claim(invite["token"])

marketplace = client.marketplace.list_programs(
    sort="commission",
    min_commission=20,
)

client.marketplace.apply(
    marketplace.data[0]["programId"],
    message="I manage affiliate agents for SaaS products.",
)
The REST SDK onboarding namespace currently covers merchant profile upsert by company_name and onboarding completion. Merchant MCP has additional setup tools for get_onboarding_status, get_tracking_snippet, and active tracking verification.

Webhooks

# List webhook endpoints
endpoints = client.webhooks.list(program_id="prog-uuid")

# Create endpoint
result = client.webhooks.create(
    name="Production Webhook",
    url="https://api.acme.com/webhooks/agentref",
    subscribed_events=[
        "conversion.created",
        "payout.completed",
        "affiliate.joined",
    ],
    program_id="prog-uuid",
)
signing_secret = result.signing_secret  # store securely -- shown only once

# Update endpoint
client.webhooks.update(
    "wh-uuid",
    subscribed_events=[
        "conversion.created",
        "conversion.refunded",
        "payout.completed",
    ],
)

# Rotate signing secret
new_result = client.webhooks.rotate_secret("wh-uuid")

# Delete endpoint
client.webhooks.delete("wh-uuid")

Pagination

Paginated REST list methods return a PaginatedResponse[T] with typed data and metadata:
result = client.programs.list(page=1, limit=25)

print(result.data)          # List[Program]
print(result.meta.total)    # Total count
print(result.meta.has_more) # More pages available?
print(result.meta.page)     # Current page
Some convenience list methods return plain lists because their REST endpoints return array data directly. Examples include client.affiliate_workspace.list_programs(), client.affiliate_workspace.list_links(), client.marketing_resources.list(), client.marketing_resources.list_for_affiliate(), client.webhooks.list(), and client.conversions.recent().

Auto-pagination

The list_all() generator handles pagination automatically:
# Sync
for program in client.programs.list_all(page_size=100):
    print(program.name)

# Async
async for program in client.programs.list_all(page_size=100):
    print(program.name)

Idempotency

POST mutation methods accept an idempotency_key keyword argument. When provided, the request is safe to retry — the server guarantees at-most-once execution.
program = client.programs.create(
    name="Acme Referrals",
    commission_type="recurring",
    commission_percent=25,
    idempotency_key="create-acme-referrals-v1",
)
The SDK automatically retries failed requests (up to max_retries) for:
  • GET/HEAD requests — always safe to retry
  • POST requests with an idempotency key — server-side deduplication
  • 429 (rate limited) and 5xx (server error) responses
POST requests without an idempotency key are never retried.

Error Handling

The SDK raises typed exceptions for all API failures:
from agentref import (
    AgentRefError,
    AuthError,
    ForbiddenError,
    ValidationError,
    NotFoundError,
    ConflictError,
    RateLimitError,
    ServerError,
)

try:
    client.programs.get("nonexistent-id")
except NotFoundError as e:
    print(f"Not found: {e}")
    print(f"Request ID: {e.request_id}")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
except ValidationError as e:
    print(f"Validation failed: {e}")
    print(f"Details: {e.details}")
except AgentRefError as e:
    print(f"API error {e.status}: {e.code} - {e}")
Exception ClassHTTP StatusWhen
AuthError401Invalid or missing API key
ForbiddenError403Key lacks required scope
ValidationError400Invalid request parameters
NotFoundError404Resource does not exist
ConflictError409Duplicate resource or state conflict
RateLimitError429Too many requests
ServerError5xxServer-side error
All exceptions inherit from AgentRefError and include code, status, and request_id attributes.

Sync vs Async

The Python SDK ships with both synchronous and asynchronous clients:
from agentref import AgentRef

client = AgentRef(api_key="ak_live_...")
programs = client.programs.list()
client.close()  # optional cleanup
The async client supports async with for automatic connection cleanup. All async resource methods are identical to their sync counterparts but return coroutines.