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 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

npm install agentref

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
});
OptionTypeDefaultDescription
apiKeystringAGENTREF_API_KEY envYour API key. Required.
baseUrlstringhttps://www.agentref.co/api/v1API base URL
timeoutnumber30000Request timeout in ms
maxRetriesnumber2Max retries for safe/idempotent requests
dangerouslyAllowBrowserbooleanfalseOverride 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:
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.affiliateWorkspaceAffiliate self-serve overview, programs, links, earnings, payouts, and clicks
client.marketingResourcesMerchant 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.payoutInfoGet and update affiliate payout 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)
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.
MethodSurface
list, createSocialPost, updateSocialPostMerchant REST/SDK
createSocialPostMediaUploadSession, completeSocialPostMediaUpload, replaceSocialPostMediaMerchant REST/SDK
reorderSocialPostMedia, updateSocialPostMedia, removeSocialPostMediaMerchant REST/SDK
publish, unpublish, archive, notifyAffiliates, createDownloadUrlMerchant REST/SDK
listForAffiliate, getForAffiliate, renderSocialPost, createAffiliateDownloadUrlAffiliate REST/SDK
Collections, external links, generic file upload, URL importMerchant 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');

Pagination

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().

Page-based pagination

const page1 = await client.programs.list({ page: 1, limit: 25 });
if (page1.meta.hasMore) {
  const page2 = await client.programs.list({ page: 2, limit: 25 });
}

Auto-pagination

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 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 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';