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 package is a lightweight, fully-typed Node.js client for the AgentRef REST API v1. It handles authentication, retries, pagination, idempotency, and structured error handling out of the box.
Installation
Quick Start
import { AgentRef } from 'agentref';
const client = new AgentRef({
apiKey: 'ak_live_your_api_key_here',
});
// List all programs
const { data: programs, meta } = await client.programs.list();
console.log(`Found ${meta.total} programs`);
// Get conversion stats
const stats = await client.conversions.stats({ period: '30d' });
console.log(`Revenue: $${stats.totalRevenue / 100}`);
Configuration
const client = new AgentRef({
apiKey: 'ak_live_...', // or set AGENTREF_API_KEY env var
baseUrl: 'https://www.agentref.co/api/v1', // default
timeout: 30_000, // 30s default
maxRetries: 2, // retries for GET + idempotent POST
});
| Option | Type | Default | Description |
|---|
apiKey | string | AGENTREF_API_KEY env | Your API key. Required. |
baseUrl | string | https://www.agentref.co/api/v1 | API base URL |
timeout | number | 30000 | Request timeout in ms |
maxRetries | number | 2 | Max retries for safe/idempotent requests |
dangerouslyAllowBrowser | boolean | false | Override browser safety check (not recommended) |
Never expose API keys in client-side code. The SDK throws an error if initialized in a browser context unless you explicitly opt in with dangerouslyAllowBrowser: true.
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.affiliateWorkspace | Affiliate self-serve overview, programs, links, earnings, payouts, and clicks |
client.marketingResources | 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.payoutInfo | Get and update affiliate payout 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)
const { data, meta } = await client.programs.list({
status: 'active',
limit: 10,
page: 1,
});
// Auto-paginate through all programs
for await (const program of client.programs.listAll()) {
console.log(program.name);
}
// Get program details (includes readiness status)
const detail = await client.programs.get('prog-uuid');
console.log(detail.readiness); // 'setup' | 'partial' | 'ready'
// Create a program
const program = await client.programs.create({
name: 'Acme Referrals',
commissionType: 'recurring',
commissionPercent: 25,
cookieDuration: 60,
currency: 'USD',
}, { idempotencyKey: 'create-acme-v1' });
// Update a program
await client.programs.update('prog-uuid', {
commissionPercent: 30,
status: 'active',
});
// Delete a program
await client.programs.delete('prog-uuid');
// Get program stats
const stats = await client.programs.stats('prog-uuid', { period: '30d' });
// List program affiliates
const affiliates = await client.programs.listAffiliates('prog-uuid', {
includeBlocked: false,
});
// Manage invites
const invite = await client.programs.createInvite('prog-uuid', {
email: 'partner@example.com',
expiresInDays: 7,
}, { idempotencyKey: 'invite-partner-v1' });
const invites = await client.programs.listInvites('prog-uuid');
// Manage coupons
const coupon = await client.programs.createCoupon('prog-uuid', {
affiliateId: 'aff-uuid',
code: 'PARTNER20',
}, { idempotencyKey: 'coupon-partner20' });
const coupons = await client.programs.listCoupons('prog-uuid');
await client.programs.deleteCoupon('coupon-uuid');
// Marketplace settings
await client.programs.updateMarketplace('prog-uuid', {
status: 'public',
category: 'SaaS',
description: 'Earn 25% recurring for every referral.',
});
// Stripe connection
const stripe = await client.programs.connectStripe('prog-uuid');
console.log(stripe.authUrl); // redirect merchant to complete OAuth
await client.programs.disconnectStripe('prog-uuid');
Applications
// Pending joins live in the Applications lifecycle
const pending = await client.applications.list({
programId: 'prog-uuid',
status: 'pending',
});
await client.applications.approve(
pending.data[0]!.id,
{ note: 'Relevant SaaS audience.' },
{ idempotencyKey: 'approve-app-123' }
);
await client.applications.decline('app-uuid', {
note: 'Audience is not a fit.',
});
Affiliates
// List approved or blocked affiliate memberships
const { data } = await client.affiliates.list({
programId: 'prog-uuid',
status: 'approved',
search: 'john',
sortBy: 'totalRevenue',
sortOrder: 'desc',
limit: 25,
});
// Get single affiliate (with optional stats)
const affiliate = await client.affiliates.get('aff-uuid', {
include: 'stats',
});
// Block with reason
await client.affiliates.block('aff-uuid', {
reason: 'Suspicious click patterns detected',
}, { idempotencyKey: 'block-aff-123' });
// Unblock
await client.affiliates.unblock('aff-uuid', {
idempotencyKey: 'unblock-aff-123',
});
Affiliate Workspace
const identity = await client.affiliateWorkspace.identity();
const overview = await client.affiliateWorkspace.overview();
const programs = await client.affiliateWorkspace.listPrograms();
const link = await client.affiliateWorkspace.createLink(
{
name: 'Pricing',
destinationPath: '/pricing',
customSlug: 'jane-review',
},
{
programId: programs[0]!.programId,
idempotencyKey: 'create-pricing-link',
}
);
const links = await client.affiliateWorkspace.listLinks({
programId: programs[0]!.programId,
});
await client.affiliateWorkspace.updateLink(
link.id,
{
name: 'Pricing - updated',
targetUrl: 'https://merchant-site.com/pricing',
isActive: true,
},
{ programId: programs[0]!.programId }
);
await client.affiliateWorkspace.deleteLink('old-link-uuid', {
programId: programs[0]!.programId,
});
const earnings = await client.affiliateWorkspace.earnings();
const programEarnings = await client.affiliateWorkspace.listProgramEarnings(
programs[0]!.programId,
{ period: '30d' }
);
const payouts = await client.affiliateWorkspace.listPayouts({
programId: programs[0]!.programId,
});
const clicks = await client.affiliateWorkspace.clickStats({
programId: programs[0]!.programId,
startDate: '2026-05-01',
});
createLink uses destinationPath and customSlug. The current update API accepts name, targetUrl, and isActive; create a new link when you need a different destination path or custom slug.
Marketing Resources
// Merchant workflow
const post = await client.marketingResources.createSocialPost(
'prog-uuid',
{
title: 'Launch copy',
body: 'Try AgentRef: {{affiliate_link}}',
platforms: ['linkedin'],
status: 'published',
},
{ idempotencyKey: 'mr-launch-copy' }
);
await client.marketingResources.publish(
post.id,
{ programId: 'prog-uuid', notifyAffiliates: true },
{ idempotencyKey: 'publish-mr-launch-copy' }
);
await client.marketingResources.updateSocialPost(post.id, {
programId: 'prog-uuid',
title: 'Launch copy v2',
});
const upload = await client.marketingResources.createSocialPostMediaUploadSession(
post.id,
{
programId: 'prog-uuid',
fileName: 'launch.png',
mimeType: 'image/png',
fileSizeBytes: 125_000,
},
{ idempotencyKey: 'launch-media-upload' }
);
// Upload the file bytes to upload.signed_url, then attach the uploaded media.
await client.marketingResources.completeSocialPostMediaUpload(
post.id,
{
programId: 'prog-uuid',
uploadPath: upload.upload_path,
uploadToken: upload.upload_token,
fileName: 'launch.png',
altText: 'Launch product screenshot',
},
{ idempotencyKey: 'launch-media-complete' }
);
await client.marketingResources.createDownloadUrl(
{ programId: 'prog-uuid', resourceId: post.id },
{ idempotencyKey: 'download-launch-copy' }
);
// Affiliate workflow
const resources = await client.marketingResources.listForAffiliate('prog-uuid', {
kind: 'social_posts',
});
const resource = await client.marketingResources.getForAffiliate(resources[0]!.id, {
programId: 'prog-uuid',
});
const rendered = await client.marketingResources.renderSocialPost(resources[0]!.id, {
programId: 'prog-uuid',
affiliateLinkId: link.id,
});
const download = await client.marketingResources.createAffiliateDownloadUrl({
programId: 'prog-uuid',
resourceId: 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, createSocialPost, updateSocialPost | Merchant REST/SDK |
createSocialPostMediaUploadSession, completeSocialPostMediaUpload, replaceSocialPostMedia | Merchant REST/SDK |
reorderSocialPostMedia, updateSocialPostMedia, removeSocialPostMedia | Merchant REST/SDK |
publish, unpublish, archive, notifyAffiliates, createDownloadUrl | Merchant REST/SDK |
listForAffiliate, getForAffiliate, renderSocialPost, createAffiliateDownloadUrl | Affiliate REST/SDK |
| Collections, external links, generic file upload, URL import | Merchant MCP only |
Conversions
// List conversions with filters
const { data, meta } = await client.conversions.list({
programId: 'prog-uuid',
status: 'pending',
startDate: '2026-01-01',
endDate: '2026-03-23',
limit: 50,
});
// Aggregate stats
const stats = await client.conversions.stats({
programId: 'prog-uuid',
period: '30d',
});
console.log(`${stats.total} conversions, $${stats.totalRevenue / 100} revenue`);
// Recent conversions
const recent = await client.conversions.recent({ limit: 5 });
Payouts
// List completed payouts
const { data } = await client.payouts.list({
status: 'completed',
startDate: '2026-01-01',
});
// List pending affiliates (ready for payout)
const pending = await client.payouts.listPending({
programId: 'prog-uuid',
});
for (const aff of pending.data) {
console.log(`${aff.name}: $${aff.pendingAmount / 100} (${aff.currency})`);
}
// Payout stats
const payoutStats = await client.payouts.stats({ period: '30d' });
// Create a payout
const payout = await client.payouts.create({
affiliateId: 'aff-uuid',
programId: 'prog-uuid',
method: 'paypal',
notes: 'March payout',
}, { idempotencyKey: 'payout-march-aff123' });
Fraud Flags
// List open flags
const { data: flags } = await client.flags.list({
status: 'open',
limit: 20,
});
// Get flag stats
const flagStats = await client.flags.stats();
console.log(`${flagStats.open} open flags`);
// Resolve a flag
await client.flags.resolve('flag-uuid', {
status: 'dismissed',
note: 'Verified legitimate traffic',
blockAffiliate: false,
}, { idempotencyKey: 'resolve-flag-abc' });
Billing
// Check current billing status
const billing = await client.billing.current();
console.log(`Tier: ${billing.tier}, Revenue: $${billing.monthlyRevenue / 100}`);
// List available tiers
const tiers = await client.billing.tiers();
// Subscribe to a tier
await client.billing.subscribe({
tier: 'growth',
}, { idempotencyKey: 'subscribe-growth-v1' });
Merchant
// Get merchant profile
const merchant = await client.merchant.get();
// Update merchant settings
await client.merchant.update({
companyName: 'Acme Inc.',
timezone: 'America/New_York',
defaultCookieDuration: 60,
});
// Notification preferences
const prefs = await client.notifications.get();
await client.notifications.update({
newAffiliate: true,
newConversion: true,
weeklyDigest: true,
});
// Payout info
const payoutInfo = await client.payoutInfo.get();
await client.payoutInfo.update({
payoutMethod: 'paypal',
paypalEmail: 'payments@acme.com',
});
Onboarding, Tracking, Invites, and Marketplace
await client.onboarding.upsertMerchantProfile({
companyName: 'Acme Inc.',
});
await client.onboarding.complete();
const tracking = await client.tracking.getProgramStatus('prog-uuid');
const invite = await client.invites.get('invite-token');
const claimed = await client.invites.claim(invite.token);
const marketplace = await client.marketplace.listPrograms({
sort: 'commission',
minCommission: 20,
});
await 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 companyName and onboarding completion. Merchant MCP has additional setup tools for get_onboarding_status, get_tracking_snippet, and active tracking verification.
Webhooks
// List webhook endpoints
const endpoints = await client.webhooks.list({
programId: 'prog-uuid',
});
// Create endpoint
const { endpoint, signingSecret } = await client.webhooks.create({
name: 'Production Webhook',
url: 'https://api.acme.com/webhooks/agentref',
subscribedEvents: [
'conversion.created',
'payout.completed',
'affiliate.joined',
],
programId: 'prog-uuid',
});
// Store signingSecret securely -- it's shown only once
// Update endpoint
await client.webhooks.update('wh-uuid', {
subscribedEvents: [
'conversion.created',
'conversion.refunded',
'payout.completed',
],
});
// Rotate signing secret
const { signingSecret: newSecret } = await client.webhooks.rotateSecret('wh-uuid');
// Delete endpoint
await client.webhooks.delete('wh-uuid');
Paginated REST list methods return a PaginatedResponse<T>:
interface PaginatedResponse<T> {
data: T[];
meta: {
total: number;
page: number;
pageSize: number;
hasMore: boolean;
nextCursor?: string;
requestId: string;
};
}
Some convenience list methods return plain arrays because their REST endpoints return array data directly. Examples include client.affiliateWorkspace.listPrograms(), client.affiliateWorkspace.listLinks(), client.marketingResources.list(), client.marketingResources.listForAffiliate(), client.webhooks.list(), and client.conversions.recent().
const page1 = await client.programs.list({ page: 1, limit: 25 });
if (page1.meta.hasMore) {
const page2 = await client.programs.list({ page: 2, limit: 25 });
}
The listAll() generator handles pagination automatically:
for await (const program of client.programs.listAll({ pageSize: 100 })) {
console.log(program.name);
}
Idempotency
All mutation methods (POST) accept an idempotencyKey option. When provided, the request is safe to retry — the server guarantees at-most-once execution.
const program = await client.programs.create({
name: 'Acme Referrals',
commissionType: 'recurring',
commissionPercent: 25,
}, {
idempotencyKey: 'create-acme-referrals-v1',
});
The SDK automatically retries failed requests (up to maxRetries) 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 throws typed errors for all API failures:
import {
AgentRefError,
AuthError,
ForbiddenError,
ValidationError,
NotFoundError,
ConflictError,
RateLimitError,
ServerError,
} from 'agentref';
try {
await client.programs.get('nonexistent-id');
} catch (error) {
if (error instanceof NotFoundError) {
console.log(`Not found: ${error.message}`);
console.log(`Request ID: ${error.requestId}`);
} else if (error instanceof RateLimitError) {
console.log(`Rate limited. Retry after ${error.retryAfter}s`);
} else if (error instanceof ValidationError) {
console.log(`Validation failed: ${error.message}`);
console.log('Details:', error.details);
} else if (error instanceof AgentRefError) {
console.log(`API error ${error.status}: ${error.code} - ${error.message}`);
}
}
| Error 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 errors extend AgentRefError and include code, status, message, and requestId properties.
TypeScript Types
All types are exported from the package:
import type {
Program,
ProgramDetail,
ProgramStats,
Application,
AffiliateLink,
MarketingResource,
RenderedMarketingSocialPost,
Affiliate,
Conversion,
ConversionStats,
Payout,
PendingAffiliate,
Flag,
FlagStats,
BillingStatus,
Merchant,
WebhookEndpoint,
PaginatedResponse,
CreateProgramParams,
UpdateProgramParams,
ResolveFlagParams,
CreatePayoutParams,
CreateWebhookEndpointParams,
// ... and more
} from 'agentref';