Agent Integration

Base URL: https://api.syndicatelinks.co

All examples use production base URL. Replace with http://localhost:3000 for local testing.

Authentication

Two key types for agents:

  • aff_agent_ — issued to autonomous agents and agent platforms. Use for machine-to-machine calls.
  • ak_live_ / aff_human_ — human affiliate keys. Agents should not use these.

Header:

Authorization: Bearer aff_agent_...

Scope vocabulary

  • merchant:* — full merchant operations (register, programs, products, reports)
  • affiliate:* — affiliate operations (links, events, payouts, analytics)
  • agent:* — agent-specific attribution and commission endpoints

Request an aff_agent_ key via POST /affiliate/register with type=agent.

Cold merchant registration

Agents can onboard merchants programmatically. The /merchant/register endpoint requires no auth.

curl

curl -X POST https://api.syndicatelinks.co/merchant/register \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Store",
    "email": "[email protected]",
    "website": "https://acme.example",
    "description": "Handcrafted tools",
    "category": "tools"
  }'

TypeScript (fetch)

const res = await fetch("https://api.syndicatelinks.co/merchant/register", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    name: "Acme Store",
    email: "[email protected]",
    website: "https://acme.example",
  }),
});
const { id, apiKey, slug } = await res.json();

Python (httpx)

import httpx

async def register_merchant():
    async with httpx.AsyncClient() as client:
        r = await client.post(
            "https://api.syndicatelinks.co/merchant/register",
            json={
                "name": "Acme Store",
                "email": "[email protected]",
                "website": "https://acme.example",
            },
        )
        data = r.json()
        return data["id"], data["apiKey"], data["slug"]

Response shape

{
  "id": "uuid",
  "name": "Acme Store",
  "email": "[email protected]",
  "slug": "acme-store",
  "apiKey": "mk_live_..."
}

The apiKey is returned once. Store it securely.

Program creation

Requires merchant key (mk_live_).

curl

curl -X POST https://api.syndicatelinks.co/merchant/programs \
  -H "Authorization: Bearer mk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Affiliate Program",
    "commissionPct": 15,
    "cookieDays": 30
  }'

TypeScript / Python examples follow the same pattern as registration — replace endpoint and auth header.

Product import

Single product

POST /merchant/products

Request

{
  "programId": "uuid",
  "name": "Hammer",
  "url": "https://acme.example/hammer",
  "price": "29.99",
  "externalId": "hammer-001",
  "commissionPct": 15
}

Bulk import

POST /merchant/products/bulk

{
  "programId": "uuid",
  "products": [
    { "name": "Hammer", "url": "...", "price": "29.99", ... },
    { "name": "Saw", "url": "...", "price": "49.99", ... }
  ]
}

Response

{ "inserted": 42 }

Two scopes:

  • code-scoped — uses a human-readable tracking code
  • merchant-scoped — uses program + merchant context only

Endpoint: POST /affiliate/links

Request (code-scoped)

{
  "programId": "uuid",
  "trackingCode": "acme-hammer-referral",
  "destinationUrl": "https://acme.example/hammer"
}

Response

{
  "id": "uuid",
  "shortUrl": "https://sl.link/abc123",
  "trackingCode": "acme-hammer-referral"
}

Conversion firing

Direct POST

POST /affiliate/events/conversion

{
  "linkId": "uuid",
  "orderId": "order-12345",
  "saleAmount": "99.00",
  "attributionMethod": "agent_token",
  "referrerContext": {
    "agent_id": "agent-uuid",
    "surface": "claude-desktop",
    "query": "best hammer for framing"
  }
}

Webhook receiver pattern

Merchants configure webhooks at POST /merchant/webhooks.

Payload signature: X-SL-Signature header (HMAC-SHA256 of body with webhook secret).

Example receiver (Node)

app.post("/webhook/sl", (req, res) => {
  const sig = req.headers["x-sl-signature"];
  const valid = verifyHmac(req.body, secret, sig);
  if (!valid) return res.status(401).send("bad sig");

  const { event, data } = req.body;
  if (event === "conversion") {
    // credit agent
  }
  res.sendStatus(200);
});

Retry behavior: 5 attempts, exponential backoff, 24h max.

Webhook configuration

Event types

  • conversion
  • click
  • payout
  • merchant.created

Signing

All webhooks include X-SL-Signature. Verify before processing.

Analytics pulls

GET /affiliate/analytics/conversions?from=2026-05-01&to=2026-06-01&cursor=...&limit=50

Response

{
  "data": [ /* ConversionEvent */ ],
  "cursor": "uuid | null",
  "hasMore": true
}

Rate limit: 120 requests per minute per key. Exceeding returns 429.

Full worked example

Reference agent that:

  1. Registers merchant (if cold)
  2. Creates program
  3. Imports products
  4. Generates tracking link
  5. Fires conversion on purchase
  6. Pulls analytics

See examples/agent-integration.ts in the SDK for complete runnable code.

Attribution skill pack

If your agent runtime supports portable skills, install the public Syndicate Links attribution pack before building the flow from scratch:

npx skills add syndicatelinks/attribution-skills

Repository: github.com/syndicatelinks/attribution-skills

The pack gives agents ready-made procedures for attribution install, agent-key issuance, and conversion testing against the authenticated Syndicate Links API. Use it alongside this API contract when you want the workflow scaffolded inside the agent rather than handwritten in application code.

Error handling + rate limits

All errors:

{ "error": "Human-readable message" }

Common codes:

  • 400 — validation
  • 401 — bad key
  • 403 — wrong key type or ownership
  • 404 — not found
  • 409 — conflict
  • 429 — rate limit

Always retry on 5xx with jitter. Do not retry 4xx except 429 (respect Retry-After).


Machine-parseable sections above are the contract. Any implementation must match the request/response shapes exactly.