Skip to main content
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.dev/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.dev/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 8 resource namespaces, each mapping to a group of REST API endpoints:
NamespaceDescription
client.programsCreate, update, delete, and list affiliate programs
client.affiliatesList, approve, block, and unblock affiliates
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 and notification preferences
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');

Affiliates

// List all affiliates
const { data } = await client.affiliates.list({
  programId: 'prog-uuid',
  status: 'pending',
  search: 'john',
  sortBy: 'totalRevenue',
  sortOrder: 'desc',
  limit: 25,
});

// Get single affiliate (with optional stats)
const affiliate = await client.affiliates.get('aff-uuid', {
  include: 'stats',
});

// Approve
await client.affiliates.approve('aff-uuid', {
  idempotencyKey: 'approve-aff-123',
});

// 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',
});

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.merchant.getNotifications();
await client.merchant.updateNotifications({
  newAffiliate: true,
  newConversion: true,
  weeklyDigest: true,
});

// Payout info
const payoutInfo = await client.merchant.getPayoutInfo();
await client.merchant.updatePayoutInfo({
  payoutMethod: 'paypal',
  paypalEmail: 'payments@acme.com',
});

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

All list endpoints return a PaginatedResponse<T>:
interface PaginatedResponse<T> {
  data: T[];
  meta: {
    total: number;
    page: number;
    pageSize: number;
    hasMore: boolean;
    nextCursor?: string;
    requestId: string;
  };
}

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,
  Affiliate,
  Conversion,
  ConversionStats,
  Payout,
  PendingAffiliate,
  Flag,
  FlagStats,
  BillingStatus,
  Merchant,
  WebhookEndpoint,
  PaginatedResponse,
  CreateProgramParams,
  UpdateProgramParams,
  ResolveFlagParams,
  CreatePayoutParams,
  CreateWebhookEndpointParams,
  // ... and more
} from 'agentref';