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 implementationQuickstart
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.
@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;
}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.
The pipeline has four stages:
- Intent classification — determine the category (electronics, travel, software…) and confidence score.
- Product matching — for each active affiliate link, check if the product name or keywords appear in the response.
- Deduplication — max one link per sentence, no duplicate products, respects
maxLinksPerResponse. - 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.
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.
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:
- A
clickIdis embedded in the tracking URL at injection time. - When the user clicks,
GET /track?c={clickId}records the click and immediately 302-redirects to the destination. - Your checkout flow passes the
clickIdto 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.
/api/v1/injectInject affiliate links into an LLM response string. Returns the monetised text with tracked Markdown links.
Request body
| Parameter | Type | Required | Description |
|---|---|---|---|
| response | string | required | The LLM response text to monetise. Markdown is preserved. |
| campaignId | string | required | The campaign ID to use for affiliate link matching. |
| mode | string | optional | 'conservative' | 'balanced' | 'aggressive'. Controls injection density. Default: 'balanced'. |
| maxLinks | number | optional | Override the mode's default max links per response. Range: 1–10. |
Request
{
"response": "I recommend the Sony WH-1000XM5 headphones...",
"campaignId": "electronics-q4",
"mode": "balanced",
"maxLinks": 3
}Response 200
{
"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"
}
]
}
}/api/v1/trackClick-tracking redirect. Records a click event then 302-redirects the visitor to the destination URL. Used automatically by injected links.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
| c | string | required | The clickId generated during inject(). 12-character nanoid. |
| l | string | required | The affiliate link shortCode (e.g. 'elec-001'). |
| dest | string | required | URL-encoded destination URL. Used as fallback if the affiliate link is not found. |
"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/api/v1/webhookRecord 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
| Parameter | Type | Required | Description |
|---|---|---|---|
| conversionId | string | required | Your internal order or transaction ID. Used for idempotency — duplicate conversionIds are ignored. |
| clickId | string | required | The clickId from the injected link URL. Pass this through your checkout flow. |
| value | number | required | Order/transaction value in the specified currency. Used to calculate commission. |
| currency | string | optional | ISO 4217 currency code. Default: 'USD'. |
| metadata | object | optional | Arbitrary JSON — orderId, customerId, product SKUs, etc. Stored with the conversion record. |
{
"conversionId": "conv_abc123",
"clickId": "abc123xyz",
"value": 349.99,
"currency": "USD",
"metadata": {
"orderId": "ORD-999",
"customerId": "cust_456"
}
}/api/v1/campaignsList all campaigns for your organisation, including link counts and 30-day performance metrics.
/api/v1/analytics/summaryAggregate analytics for your organisation over a configurable window. Returns KPIs, daily series, and top-performing links.
SDK Reference
@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.
// 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
| Parameter | Type | Required | Description |
|---|---|---|---|
| apiKey | string | required | Your API key. Keep server-side only. |
| campaignId | string | optional | Scope to a specific campaign's affiliate links. Omit for all active links. |
| mode | string | optional | 'conservative' | 'balanced' | 'aggressive'. Controls confidence threshold and max links. Default: 'balanced'. |
| attributionWindow | number | optional | Days a click is eligible for conversion attribution. Default: 30. |
| maxLinksPerResponse | number | optional | Hard 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.
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
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_BODY | Request body failed schema validation. Check required fields and field names. |
| 401 | MISSING_API_KEY | X-LinkAffix-Key header is absent. |
| 401 | INVALID_API_KEY | The API key is not recognised. Check your key in Settings → API Keys. |
| 409 | DUPLICATE_CONVERSION | conversionId has already been recorded. |
| 422 | CLICK_NOT_FOUND | The clickId in the webhook payload has no matching click record. |
| 422 | ATTRIBUTION_EXPIRED | The click is outside the campaign's attribution window. |
| 429 | RATE_LIMITED | Exceeded 1000 requests per minute. Back off and retry. |
| 500 | INJECT_ERROR | Unexpected 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.
- Join Amazon Associates at affiliate-program.amazon.com. Your application is usually approved within 24–48 hours.
- 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. - Build affiliate URLs by appending your tag:bash
https://amazon.com/dp/B09XS7JWHH?tag=yourname-20 - Create a campaign in the dashboard (Campaigns → New). Set commission type to percentageand enter Amazon’s category rate (typically 1–10%).
- Import your affiliate links via CSV. Go to Links → Import CSV in the dashboard. Your CSV needs at minimum
productNameandaffiliateUrlcolumns. Addingkeywords(comma-separated product terms) dramatically improves match quality. Download the template from the import dialog for a ready-to-fill example. - 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.
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
// 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
// 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 },
}),
});
}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.
// 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.
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