Developer Documentation

API Docs

Everything you need to add affiliate monetisation to your AI product — from a first inject() call to advanced attribution analytics.

v1 · REST API · Docs reflect the current implementation

Quickstart

Up and running in 5 minutes. The inject API intercepts your LLM responses, finds product mentions, and wraps them in tracked affiliate links — all server-side, no browser SDK required.

Integration

The inject engine is available today as a REST API — no package installation required. A typed SDK wrapper is on the roadmap but is not yet published to npm.

There is no @linkaffix/sdk npm package yet. Use the REST API directly (shown below). Set your API key in the X-LinkAffix-Key header.

First call

The core is a single HTTP endpoint: POST /api/v1/inject. Pass it any LLM response string and get back a monetised version with tracked links.

// No SDK package yet — call the REST API directly.
// (A typed SDK wrapper is planned but not yet published.)

export async function handleLlmResponse(text: string) {
  const res = await fetch("https://your-app.com/api/v1/inject", {
    method:  "POST",
    headers: {
      "X-LinkAffix-Key": process.env.LINKAFFIX_API_KEY!,
      "Content-Type":   "application/json",
    },
    body: JSON.stringify({
      response:   text,           // the LLM response string
      campaignId: "electronics-q4",
      mode:       "balanced",     // conservative | balanced | aggressive
    }),
  });

  const result = await res.json();

  // result.monetised — drop-in replacement for the original text
  // result.linksInjected — how many links were added
  // result.metadata.matchedProducts — which products were matched

  console.log(`Injected ${result.linksInjected} links`);

  return result.monetised;
}
The monetised field is a drop-in replacement for your original LLM output. It’s valid Markdown — links are already in [text](url) format.

Core Concepts

How injection works

The inject API sits between your LLM and your users. Every response passes through a lightweight classification and matching pipeline before being returned.

LLM Response
Intent Classify
Product Match
LLM Response
Monetised ✓
Link Inject
your app sendsclassifies intentmatches products

The pipeline has four stages:

  1. Intent classification — determine the category (electronics, travel, software…) and confidence score.
  2. Product matching — for each active affiliate link, check if the product name or keywords appear in the response.
  3. Deduplication — max one link per sentence, no duplicate products, respects maxLinksPerResponse.
  4. Injection — wrap the first mention of each matched product in a tracked Markdown link, fire-and-forget a click record.

Attribution model

The platform uses last-click attribution with a configurable window (default 30 days). When a user clicks an injected link, a clickId is recorded. When a conversion fires via webhook, the platform matches it to the most recent eligible click within the attribution window.

── clickId lifecycle ──────────────────
1. inject() → generates clickId, stores pending Click row
2. user clicks link → GET /track redirects, marks click as active
3. conversion fires → POST /webhook with clickId creates Conversion
4. attribution → commissionAmount = conversionValue × commissionRate
5. payout → monthly batch, status: pending → approved → paid

If a user clicks multiple links before converting, the most recent click within the window wins. Clicks older than the attribution window are ineligible even if no newer click exists.

Intent classification

Before matching products, the API classifies the LLM response’s intent. A high-confidence intent score unlocks more link injections; a low score suppresses injection to avoid irrelevant links.

// Example intent result
{
category: "electronics",
confidence: 0.84,
signals: ["Sony", "headphones", "recommend"],
hasRecommendationSignal: true,
hasPurchaseSignal: false
}

The confidence threshold is set per mode:

  • conservative — threshold 0.55, max 1 link. Best for sensitive content areas.
  • balanced — threshold 0.38, max 3 links. The recommended default.
  • aggressive — threshold 0.22, max 5 links. Maximises revenue but watch quality.

Cookieless tracking

Traditional affiliate tracking sets a third-party cookie on click. This breaks in two ways for AI products: the LLM generates text server-side (no browser, no cookie), and modern browsers increasingly block third-party cookies entirely.

The platform’s approach is fully server-side:

  1. A clickId is embedded in the tracking URL at injection time.
  2. When the user clicks, GET /track?c={clickId} records the click and immediately 302-redirects to the destination.
  3. Your checkout flow passes the clickId to the webhook — no cookie needed.

For deduplication, the platform hashes the visitor’s IP + User-Agent into a 16-char fingerprint. No personal data is stored.


API Reference

All endpoints are under /api/v1/. Authenticate with your API key in the X-LinkAffix-Key header.

The API key is a server-to-server secret. Never expose it in client-side JavaScript or public repositories.
POST/api/v1/inject

Inject affiliate links into an LLM response string. Returns the monetised text with tracked Markdown links.

Request body

ParameterTypeRequiredDescription
responsestringrequiredThe LLM response text to monetise. Markdown is preserved.
campaignIdstringrequiredThe campaign ID to use for affiliate link matching.
modestringoptional'conservative' | 'balanced' | 'aggressive'. Controls injection density. Default: 'balanced'.
maxLinksnumberoptionalOverride the mode's default max links per response. Range: 1–10.

Request

json
{
  "response":   "I recommend the Sony WH-1000XM5 headphones...",
  "campaignId": "electronics-q4",
  "mode":       "balanced",
  "maxLinks":   3
}

Response 200

json
{
  "monetised":      "I recommend the [Sony WH-1000XM5](<tracked-url>) headphones...",
  "original":       "I recommend the Sony WH-1000XM5 headphones...",
  "linksInjected":  1,
  "estimatedValue": 0.0045,
  "clickIds":       ["abc123xyz"],
  "metadata": {
    "intent":          "electronics",
    "processingMs":    18,
    "matchedProducts": [
      {
        "productName":     "Sony WH-1000XM5",
        "affiliateLinkId": "clxyz...",
        "shortCode":       "elec-001",
        "destinationUrl":  "https://amazon.com/dp/B09XS7JWHH",
        "relevanceScore":  0.87,
        "category":        "electronics"
      }
    ]
  }
}
GET/api/v1/track

Click-tracking redirect. Records a click event then 302-redirects the visitor to the destination URL. Used automatically by injected links.

Query parameters

ParameterTypeRequiredDescription
cstringrequiredThe clickId generated during inject(). 12-character nanoid.
lstringrequiredThe affiliate link shortCode (e.g. 'elec-001').
deststringrequiredURL-encoded destination URL. Used as fallback if the affiliate link is not found.
bash
"tok-prompt">$ curl -v 'https://your-app.com/api/v1/track?c=abc123&l=elec-001&dest=https%3A%2F%2Famazon.com%2Fdp%2FB09XS7JWHH'
# → HTTP/1.1 302 Found
# → Location: https://amazon.com/dp/B09XS7JWHH
The redirect is synchronous. Click recording happens asynchronously so latency is minimal — typically under 2 ms overhead.
POST/api/v1/webhook

Record a conversion event. Call this from your server when a purchase is completed. The platform matches the clickId to the originating affiliate link and records commission.

Request body

ParameterTypeRequiredDescription
conversionIdstringrequiredYour internal order or transaction ID. Used for idempotency — duplicate conversionIds are ignored.
clickIdstringrequiredThe clickId from the injected link URL. Pass this through your checkout flow.
valuenumberrequiredOrder/transaction value in the specified currency. Used to calculate commission.
currencystringoptionalISO 4217 currency code. Default: 'USD'.
metadataobjectoptionalArbitrary JSON — orderId, customerId, product SKUs, etc. Stored with the conversion record.
POST body
{
  "conversionId": "conv_abc123",
  "clickId":      "abc123xyz",
  "value":        349.99,
  "currency":     "USD",
  "metadata": {
    "orderId":    "ORD-999",
    "customerId": "cust_456"
  }
}
GET/api/v1/campaigns

List all campaigns for your organisation, including link counts and 30-day performance metrics.

This endpoint is not yet implemented. Campaign data is currently available only through the dashboard UI. It will be added in a future release.
GET/api/v1/analytics/summary

Aggregate analytics for your organisation over a configurable window. Returns KPIs, daily series, and top-performing links.

This endpoint is not yet implemented. Analytics are currently available only through the dashboard UI. It will be added in a future release.

SDK Reference

The SDK package is not yet published. There is no @linkaffix/sdk on npm. This section documents the planned interface — use the REST API directly until the SDK is released.

linkaffix.inject() — planned

Planned SDK function. Shown here for interface design reference. Until the package is published, make direct fetch() calls to POST /api/v1/inject.

typescript
// SDK package planned — not yet published.
// Use the REST API directly for now (see Quickstart).

// Planned interface (subject to change):
// import { linkaffix, type LinkAffixConfig } from '@linkaffix/sdk';
//
// const config: LinkAffixConfig = {
//   apiKey:               process.env.LINKAFFIX_API_KEY!,
//   campaignId:           'electronics-q4',
//   mode:                 'balanced',
//   attributionWindow:    30,
//   maxLinksPerResponse:  3,
// };
//
// const result: InjectionResult = await linkaffix.inject(llmText, config);

LinkAffixConfig — planned

ParameterTypeRequiredDescription
apiKeystringrequiredYour API key. Keep server-side only.
campaignIdstringoptionalScope to a specific campaign's affiliate links. Omit for all active links.
modestringoptional'conservative' | 'balanced' | 'aggressive'. Controls confidence threshold and max links. Default: 'balanced'.
attributionWindownumberoptionalDays a click is eligible for conversion attribution. Default: 30.
maxLinksPerResponsenumberoptionalHard cap on links per inject() call. Overrides the mode default.

InjectionResult — REST API response shape

The JSON response from POST /api/v1/inject. All fields are always present — linksInjected will be 0 when no matches are found.

typescript
interface InjectionResult {
  /** Original unmodified text */
  original:       string;

  /** Text with affiliate links injected (Markdown) */
  monetised:      string;

  /** Number of links successfully injected */
  linksInjected:  number;

  /** CPM-based estimated value in USD */
  estimatedValue: number;

  /** One clickId per injected link — store for attribution */
  clickIds:       string[];

  metadata: {
    /** Detected intent category */
    intent:          string;

    /** Products that were matched and injected */
    matchedProducts: MatchedProduct[];

    /** Processing time in milliseconds */
    processingMs:    number;
  };
}

interface MatchedProduct {
  productName:     string;
  affiliateLinkId: string;
  shortCode:       string;
  destinationUrl:  string;
  relevanceScore:  number;   // 0–1
  category:        string;
}

Error codes

HTTPCodeDescription
400INVALID_BODYRequest body failed schema validation. Check required fields and field names.
401MISSING_API_KEYX-LinkAffix-Key header is absent.
401INVALID_API_KEYThe API key is not recognised. Check your key in Settings → API Keys.
409DUPLICATE_CONVERSIONconversionId has already been recorded.
422CLICK_NOT_FOUNDThe clickId in the webhook payload has no matching click record.
422ATTRIBUTION_EXPIREDThe click is outside the campaign's attribution window.
429RATE_LIMITEDExceeded 1000 requests per minute. Back off and retry.
500INJECT_ERRORUnexpected server error. Retry with exponential backoff.

Guides

Connecting Amazon Associates

Amazon Associates is the most common affiliate network for product recommendations. Here’s how to connect it to this platform.

  1. Join Amazon Associates at affiliate-program.amazon.com. Your application is usually approved within 24–48 hours.
  2. Get your tracking ID — it looks like yourname-20. In Amazon’s dashboard, go to Tools → Product Linking → Link Builder and grab the base product URL.
  3. Build affiliate URLs by appending your tag:
    bash
    https://amazon.com/dp/B09XS7JWHH?tag=yourname-20
  4. Create a campaign in the dashboard (Campaigns → New). Set commission type to percentageand enter Amazon’s category rate (typically 1–10%).
  5. Import your affiliate links via CSV. Go to Links → Import CSV in the dashboard. Your CSV needs at minimum productName and affiliateUrl columns. Adding keywords (comma-separated product terms) dramatically improves match quality. Download the template from the import dialog for a ready-to-fill example.
  6. Set up conversion tracking. Amazon Associates doesn’t offer real-time webhooks. You’ll need to reconcile conversions manually or via their reporting API — automatic reconciliation is not built yet. See Setting up conversion webhooks below for the general webhook approach.
Amazon requires you disclose affiliate relationships. Add a brief disclosure to your product’s UI, e.g. “Some links are affiliate links — we may earn a commission.” See the IAB compliance checklist below.

Setting up conversion webhooks

Conversion tracking closes the attribution loop. When a user completes a purchase that started from an injected affiliate link, your server fires a webhook to record it.

The critical piece is passing the clickId through your checkout flow:

Step 1 — Store the clickId on click

typescript
// On your tracking redirect (or via the redirect params)
// Extract the clickId and store in the user's session
app.get('/go/:shortCode', (req, res) => {
  const { c: clickId } = req.query;
  req.session.linkaffixClickId = clickId;
  // ... redirect to affiliate URL
});

Step 2 — Fire the webhook on conversion

typescript
// In your order-confirmation handler
export async function onOrderComplete(order: Order) {
  const clickId = order.sessionData?.linkaffixClickId;
  if (!clickId) return;

  await fetch('https://your-app.com/api/v1/webhook', {
    method: 'POST',
    headers: {
      'X-LinkAffix-Key': process.env.LINKAFFIX_API_KEY!,
      'Content-Type':   'application/json',
    },
    body: JSON.stringify({
      conversionId: order.id,
      clickId,
      value:    order.total,
      currency: 'USD',
      metadata: { orderId: order.id },
    }),
  });
}
No cookie access in your checkout? Pass the clickId as a URL parameter through your entire funnel (e.g. ?wid=abc123) and read it from the final confirmation page.

A/B testing injection density

Different injection densities perform differently depending on your product. Use the mode parameter to run controlled experiments.

typescript
// Randomise mode per session to A/B test injection density
const mode = Math.random() < 0.5 ? 'conservative' : 'aggressive';

const res = await fetch('https://your-app.com/api/v1/inject', {
  method:  'POST',
  headers: { 'X-LinkAffix-Key': process.env.LINKAFFIX_API_KEY!, 'Content-Type': 'application/json' },
  body: JSON.stringify({ response: text, campaignId: 'electronics-q4', mode }),
});
const result = await res.json();

// Log to your analytics
analytics.track('injection', {
  mode,
  linksInjected: result.linksInjected,
});

Analyse results in the Analytics dashboard — filter by campaign and compare CVR across modes. The hypothesis is that balanced will outperform aggressive on CVR because users are less likely to feel the response is commercially biased. Run the experiment with your own data to verify.

IAB compliance checklist

The IAB Tech Lab and FTC guidelines require disclosure when AI-generated content contains affiliate links. Here’s what you need:

Disclose affiliate links

Add a visible disclosure label near AI responses that contain affiliate links, e.g. 'This response may contain affiliate links.'

Don't manipulate recommendations

The AI's recommendation must be genuine. The API injects links for products already mentioned — never for products the AI wouldn't otherwise suggest.

Respect user opt-out

Provide a mechanism for users to opt out of monetised responses. Honor it on the server by calling inject() conditionally.

Data retention limits

Click and conversion data must not be retained beyond your stated data policy. The platform stores click IDs and hashed IPs only — no PII.

Clear labelling

If surfacing affiliate links in a list or comparison UI, mark them clearly (e.g. 'Ad' or 'Sponsored').

Privacy policy

Update your privacy policy to disclose that LLM responses may contain affiliate tracking links.

The IAB Tech Lab has active working groups on AI-driven content and attribution. This checklist reflects current FTC and IAB guidelines — check the IAB Tech Lab site directly for the latest standards.

Changelog

June 2025

2025-06-01

Current
  • Inject + track endpoints working
  • Balanced / conservative / aggressive injection modes
  • Last-click attribution engine
  • Dashboard: overview, campaigns, analytics, publishers
  • Demo page with seeded Amazon Associates + Booking.com data

May 2025

2025-05-15

Prior
  • Attribution engine with configurable window (1–90 days)
  • Conversion webhook endpoint
  • Commission rate support: percentage + fixed
  • Payout queue (pending → approved → paid)

April 2025

2025-04-28

Prior
  • Campaign management UI
  • Affiliate link CRUD
  • Intent classification v1 (electronics, travel, software, finance, home)
  • Click deduplication via IP+UA hashing

Full changelog at /blog#changelog