How Agent Attribution Works

Overview

This document explains how an AI agent earns commission on conversions it drives through the Syndicate Links attribution system. Two core problems make traditional affiliate tracking unworkable in agent contexts: (1) cookies are unavailable — agents operate outside browsers and have no cookie jar to read or write, and (2) there is no shared session between the agent and the merchant — the agent cannot inject tracking state into a user's browsing context. The system described here solves both problems with a two-layer, machine-to-machine credential model that requires no browser, no redirect, and no session.


Two-Layer Auth Model

Every conversion event must carry two independent authentication signals. Neither is sufficient on its own.

LayerToken FormatPurpose
Layer 1aff_agent_… Bearer tokenProves who is calling — identifies the registered affiliate
Layer 2slat_v1_… attribution tokenProves the event is legitimate — binds the call to a specific affiliate-program relationship and a unique nonce

Layer 1 (aff_agent_ Bearer token) is a long-lived credential issued to a registered publisher. It authenticates the caller at the API boundary — confirming that the request comes from a known affiliate account. It does not by itself prove the event is bound to a valid program or that it hasn't been replayed.

Layer 2 (slat_v1_ attribution token) is a short-lived, HMAC-signed token minted at conversion time. It encodes the affiliate ID, program ID, tracking code, and a unique nonce. Its signature proves the token was created by a party with access to the affiliate's token secret, and the nonce prevents replay. It does not by itself prove the caller has valid API access.

Both layers must pass validation for a conversion event to be recorded.


Agent Key Flow

Agent keys are issued through the Syndicate Links affiliate publisher portal.

Registration

Register as a publisher at affiliate.syndicatelinks.co. After registration, your affiliateId is assigned and available in the portal dashboard.

Issuing an Agent Key

POST /affiliate/keys
Authorization: Bearer <your-session-token>
Content-Type: application/json

{
  "type": "agent",
  "label": "my-agent-v1"
}

Response:

{
  "key": "aff_agent_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "type": "agent",
  "label": "my-agent-v1",
  "createdAt": "2026-04-03T00:00:00.000Z"
}

Key Handling

Agent keys are long-lived. They do not expire on a schedule, but can be revoked via the portal or API. Treat them as secrets:

  • Store in a secret manager (e.g., AWS Secrets Manager, Vault, environment secrets in your deployment platform)
  • Do not commit to source control
  • Do not log the key value
  • Rotate if compromised — issue a new key and revoke the old one

Attribution Token (slat_v1_) Format

Structure

slat_v1_{base64url(JSON payload)}.{HMAC-SHA256-hex}

The token is a dot-separated string. The prefix slat_v1_ is a literal string identifying the token type and version. The payload is standard base64url-encoded JSON (no padding). The signature is a lowercase hex-encoded HMAC-SHA256 of the full string slat_v1_{base64url(payload)} using the AGENT_TOKEN_SECRET.

Payload Fields

FieldTypeRequiredDescription
substringYesAffiliate ID — must match the affiliateId of the authenticated aff_agent_ key
progstringYesProgram ID of the merchant program being attributed
codestringYesTracking code for the program (assigned when you join)
noncestring (UUID v4)YesUnique identifier for this event — used for replay protection
iatnumberYesToken issuance time as Unix timestamp (seconds)
expnumberNoOptional expiry as Unix timestamp (seconds) — server rejects tokens past this time

Example Payload

{
  "sub": "aff_01HXYZ1234567890",
  "prog": "prog_01HABC9876543210",
  "code": "AGENTSPRING2026",
  "nonce": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
  "iat": 1743638400
}

Signing

HMAC-SHA256(
  key  = AGENT_TOKEN_SECRET,
  data = "slat_v1_" + base64url(JSON.stringify(payload))
)

The AGENT_TOKEN_SECRET is available in your affiliate dashboard under Settings → Agent Token Secret. It is scoped to your affiliate account.

Minting Timing

Tokens are minted at conversion time — not in advance. A token represents a specific conversion event. Do not cache or reuse tokens across events; each conversion requires a fresh nonce and a new token.

Example: Minting in Node.js

import crypto from 'crypto';

function mintAttributionToken({ affiliateId, programId, trackingCode, secret }) {
  const payload = {
    sub: affiliateId,
    prog: programId,
    code: trackingCode,
    nonce: crypto.randomUUID(),
    iat: Math.floor(Date.now() / 1000),
  };

  const encodedPayload = Buffer.from(JSON.stringify(payload))
    .toString('base64url');

  const data = `slat_v1_${encodedPayload}`;

  const sig = crypto
    .createHmac('sha256', secret)
    .update(data)
    .digest('hex');

  return `${data}.${sig}`;
}

Replay Protection

Nonce Deduplication

Every slat_v1_ token includes a nonce — a UUID v4 generated fresh for each conversion event. The server stores nonces with a 48-hour TTL.

ScenarioServer behavior
First time this nonce is seenEvent is recorded, 201 returned
Same nonce received again within 48h409 returned — event already recorded
Same nonce received after 48hNonce slot is freed; a new event would be recorded (avoid this — always use a fresh nonce)

How to Handle 409

A 409 response on a conversion attempt means the server already has a record for this event. Treat 409 as success. Do not retry with the same token. Do not generate a new token for the same underlying conversion — that would create a duplicate commission claim.

The canonical pattern:

const res = await fetch('/v1/track/agent-attribution', { ... });

if (res.status === 201 || res.status === 409) {
  // Event recorded (201) or already recorded (409) — both are success
  return;
}

// Handle other status codes as errors

Auto-Approved Commissions

When POST /v1/track/agent-attribution returns 201, the commission is immediately recorded with commissionStatus: "approved". There is no manual review gate before approval.

201 Response Body

{
  "eventId": "evt_01HXYZ9999999999",
  "commissionAmount": 12.50,
  "commissionStatus": "approved",
  "programId": "prog_01HABC9876543210",
  "recordedAt": "2026-04-03T00:00:00.000Z"
}

commissionAmount is in the currency configured by the merchant for the program. commissionStatus will always be "approved" in a 201 response — pending fraud scoring (see next section).


Fraud Scoring

Fraud scoring is asynchronous and non-blocking. The 201 is returned before fraud scoring completes. Scoring runs in the background after the event is recorded.

Signals

SignalDescription
Order ID reuseSame order ID claimed by more than one agent key
Commission velocityAnomalous rate of successful attributions from a single affiliate
Token signature qualityStatistical patterns in nonce or payload fields inconsistent with normal minting behavior

Post-Approval Flagging

High-confidence fraud signals can result in an event being flagged or reversed after the initial 201. When this happens, commissionStatus transitions from "approved" to "flagged" or "reversed". Webhooks are fired for status transitions if you have a webhook endpoint configured.

Fraud scoring does not block the 201. Your agent should not poll for fraud status before proceeding.


Full Request Flow

1. Agent joins a merchant program
       ↓
2. Agent retrieves the program's trackingCode
       ↓
3. At conversion time: agent mints a slat_v1_ token
       ↓
4. Agent sends POST /v1/track/agent-attribution
       ↓
5. Server validates (see below)
       ↓
6. Server returns 201 with commissionAmount
       ↓
7. Fraud scoring runs async (non-blocking)

Step-by-Step

Step 1 — Join a program. Use the affiliate portal at affiliate.syndicatelinks.co or POST /affiliate/programs/{programId}/join via API. The program must be active and accepting affiliates.

Step 2 — Get the tracking code. After joining, the program record includes a trackingCode scoped to your affiliate account for that program. Retrieve it from the portal or via GET /affiliate/programs/{programId}/membership.

Step 3 — Mint the token at conversion time. Use your AGENT_TOKEN_SECRET to mint a slat_v1_ token. Include a fresh UUID v4 as nonce. Do not reuse tokens.

Step 4 — Send the attribution request.

POST /v1/track/agent-attribution
Authorization: Bearer aff_agent_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/json

{
  "attribution_token": "slat_v1_eyJzdWIiOiJhZmZfMDF...<payload>.3a9f1c2d...<sig>",
  "order_id": "order_12345",
  "amount": 99.00,
  "currency": "USD"
}

order_id, amount, and currency are required fields alongside attribution_token.

Step 5 — Server validation. The server validates in this order:

  • (a) Bearer token is a valid aff_agent_ key belonging to an active affiliate account
  • (b) slat_v1_ signature is valid (HMAC-SHA256 matches)
  • (c) Token sub matches the affiliateId of the authenticated Bearer key
  • (d) Nonce has not been seen in the past 48 hours
  • (e) Program (prog) is active and the affiliate is a member

If any check fails, the appropriate error code is returned (see Error Reference). No partial recording occurs.

Step 6 — 201 returned. Commission is recorded immediately with commissionStatus: "approved".

Step 7 — Async fraud scoring. Fraud scoring runs after the response is sent. Does not affect the 201 or block the agent.


Error Reference

StatusMeaningAction
400Missing required fields (attribution_token, order_id, amount, or currency absent or malformed)Fix the request body
401Invalid Bearer token, or slat_v1_ signature mismatchCheck aff_agent_ key and AGENT_TOKEN_SECRET; verify signing logic
403Attribution token sub does not match the authenticated affiliateToken was minted with a different affiliateId than the Bearer key belongs to
404Program not found or inactiveVerify prog field; check program status in the portal
409Nonce replay — event already recordedTreat as success; do not retry
429Rate limitedBack off and retry with exponential backoff
500Server errorRetry with backoff; contact support if persistent

Design Principles

  • No cookies, no browser sessions, no redirects required. Attribution is recorded via a direct API call from the agent to the Syndicate Links server. No client-side tracking infrastructure is involved.
  • Client-side token minting. The agent generates the slat_v1_ token locally using its AGENT_TOKEN_SECRET. No pre-flight request to obtain a token is needed — one round-trip records the conversion.
  • Stateless from the agent's perspective. The agent holds two secrets (aff_agent_ key and AGENT_TOKEN_SECRET) and mints tokens on demand. There is no session to maintain, no token refresh, and no handshake sequence.
  • Nonce deduplication is fully server-side. The agent generates a UUID v4 and includes it in the token. The server is solely responsible for tracking seen nonces and enforcing the 48h TTL. The agent has no obligation to remember past nonces.
  • Not OAuth. This is machine-to-machine credential binding. There is no user delegation, no authorization code flow, no token exchange, and no scopes. The aff_agent_ key represents the affiliate, not an end user.