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
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
)
| Parameter | Type | Default | Description |
|---|
api_key | str | AGENTREF_API_KEY env | Your API key. Required. |
base_url | str | https://www.agentref.co/api/v1 | API base URL |
timeout | float | 30.0 | Request timeout in seconds |
max_retries | int | 2 | Max retries for safe/idempotent requests |
Resource Namespaces
The client exposes the full REST API v1 surface through resource namespaces:
| Namespace | Description |
|---|
client.programs | Create, update, delete, and list affiliate programs |
client.applications | Review pending affiliate applications before they become memberships |
client.affiliates | List approved memberships, block, and unblock affiliates |
client.affiliate_workspace | Affiliate self-serve overview, programs, links, earnings, payouts, and clicks |
client.marketing_resources | Merchant and affiliate Marketing Resources workflows |
client.conversions | List conversions, get stats, and fetch recent activity |
client.payouts | List payouts, pending affiliates, stats, and create payouts |
client.flags | List fraud flags, get stats, and resolve flags |
client.billing | Check billing status, list tiers, and subscribe |
client.merchant | Get and update merchant profile |
client.notifications | Get and update notification preferences |
client.payout_info | Get and update payout payment details |
client.onboarding | Complete onboarding setup calls |
client.tracking | Read program tracking health |
client.invites | Inspect and claim public invite links |
client.marketplace | Discover marketplace programs and apply as an affiliate |
client.webhooks | Create, 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.
| Method | Surface |
|---|
list, create_social_post, update_social_post | Merchant REST/SDK |
create_social_post_media_upload_session, complete_social_post_media_upload, replace_social_post_media | Merchant REST/SDK |
reorder_social_post_media, update_social_post_media, remove_social_post_media | Merchant REST/SDK |
publish, unpublish, archive, notify_affiliates, create_download_url | Merchant REST/SDK |
list_for_affiliate, get_for_affiliate, render_social_post, create_affiliate_download_url | Affiliate REST/SDK |
| Collections, external links, generic file upload, URL import | Merchant 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")
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().
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 Class | HTTP Status | When |
|---|
AuthError | 401 | Invalid or missing API key |
ForbiddenError | 403 | Key lacks required scope |
ValidationError | 400 | Invalid request parameters |
NotFoundError | 404 | Resource does not exist |
ConflictError | 409 | Duplicate resource or state conflict |
RateLimitError | 429 | Too many requests |
ServerError | 5xx | Server-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.