Syndicate Links ACP Developer Reference
Version: 2.3 Audience: AI agent developers integrating with Syndicate Links Last updated: 2026-03-27 Status: Live — all endpoints production-verified
This document covers the ACP attribution API and Stripe MPP integration for agent developers.
Overview
Syndicate Links is an attribution and commission infrastructure layer built for the agent-native web. If you're building an AI agent that recommends products, drives purchases, or influences e-commerce decisions, Syndicate Links gives you the tooling to track those conversions, receive commission, and prove causation — without relying on cookies, browser sessions, or user-level tracking that doesn't translate to agent contexts.
This document covers two live integration surfaces:
- Part 1 — Stripe MPP: Machine payment plan discovery and checkout
- Part 2 — ACP Attribution: Agent-native conversion tracking and commission
Part 1: Stripe MPP
Machine Payments Discovery
GET /.well-known/machine-payments
Returns a discovery document describing the platform's machine payment capabilities. No auth required.
Plan Catalog
GET /mpp/plans
Returns the full plan tier catalog (6 tiers). No auth required.
Checkout Session
POST /mpp/checkout
Authorization: Bearer <your-account-token>
Content-Type: application/json
Creates a Stripe MPP checkout session. See syndicatelinks.co/docs for current request/response schema.
Part 2: ACP Attribution
What the ACP Attribution Layer Provides
The ACP attribution layer is built for agents operating programmatically — voice, chat, API pipelines, autonomous flows. It adds:
- Agent-scoped keys (
aff_agent_format) tied to agent identity, not account or user session - Signed attribution tokens (
slat_v1) binding each conversion event to the agent key - Nonce-based replay protection with a 48h dedup window
- Agent commission tracking queryable by agent key
Authentication
POST /affiliate/keys
Issues a new agent key. Use your account-level key to authenticate this request.
POST /affiliate/keys
Authorization: Bearer ak_live_<your-account-key>
Content-Type: application/json
{
"type": "agent"
}
Response 201:
{
"key": "aff_agent_<identifier>",
"type": "agent"
}
Store this key securely. Long-lived credential — do not embed in client-side code or expose in logs.
Two-Layer Auth
Once you have an agent key, the ACP attribution API uses a two-layer auth model:
| Layer | Purpose |
|---|---|
Bearer token (aff_agent_) | Authenticates who is calling |
slat_v1 attribution token | Authenticates the event itself — bound to agent key and nonce, replay-resistant |
Layer 1:
Authorization: Bearer aff_agent_<identifier>
Layer 2: A short-lived signed token minted client-side, sent in the request body. The server validates the signature independently.
Token Format
slat_v1_{base64url(payload)}.{HMAC-SHA256-sig}
Payload Structure
{
"agent_key": "aff_agent_<identifier>",
"nonce": "<uuid-v4>",
"timestamp": 1743000000,
"orderId": "<your-order-id>"
}
| Field | Type | Description |
|---|---|---|
agent_key | string | Your aff_agent_ key |
nonce | string | UUID v4, unique per event — 48h dedup window |
timestamp | integer | Unix seconds. 5-minute validity window |
orderId | string | Your order/conversion reference |
Signing (Python)
import hmac, hashlib, json, base64, uuid, time
def mint_slat_token(agent_key: str, order_id: str) -> str:
payload = {
"agent_key": agent_key,
"nonce": str(uuid.uuid4()),
"timestamp": int(time.time()),
"orderId": order_id,
}
encoded = base64.urlsafe_b64encode(
json.dumps(payload, separators=(",", ":")).encode()
).rstrip(b"=").decode()
sig = hmac.new(agent_key.encode(), encoded.encode(), hashlib.sha256).hexdigest()
return f"slat_v1_{encoded}.{sig}"
Server validation: re-derive HMAC, compare. Mismatch → 401. Seen nonce → 409.
POST /v1/track/ai-referral
Records an agent-driven referral click and returns the merchant destination URL for redirect handoff.
Auth: Bearer aff_agent_<identifier>
Request body:
{
"trackingCode": "agent-link-1",
"ipHash": "optional-stable-hash",
"userAgent": "Mozilla/5.0 ...",
"country": "US",
"deviceType": "desktop",
"referrer": "https://chat.openai.com/"
}
Response 201:
{
"clickId": "uuid",
"trackingCode": "agent-link-1",
"redirectUrl": "https://merchant.test/product",
"attributionMethod": "ai_referral",
"duplicate": false
}
If a matching ipHash was already seen for the same tracking link in the last 60 seconds, returns 200 with duplicate: true and does not insert a second click.
POST /v1/track/agent-attribution
Records an attribution event for a conversion.
Auth: Bearer aff_agent_<identifier>
Request body:
{
"attribution_token": "slat_v1_<payload>.<sig>",
"orderId": "order_7891234",
"saleAmount": 149.99,
"currency": "USD",
"mpp_reference": "<optional>",
"acp_transaction_token": "<optional>"
}
| Field | Required | Description |
|---|---|---|
attribution_token | ✅ | Signed slat_v1 token |
orderId | ✅ | Unique order/conversion reference |
saleAmount | ✅ | Numeric sale value |
currency | ❌ | ISO 4217 code (default: "USD") |
mpp_reference | ❌ | Marketplace or partner platform reference |
acp_transaction_token | ❌ | ACP framework session token for cross-pipeline correlation |
Response 201:
{
"eventId": "uuid",
"affiliateId": "uuid",
"programId": "uuid",
"orderId": "order_7891234",
"saleAmount": "149.99",
"commissionAmount": "14.99",
"commissionStatus": "approved",
"attributionMethod": "agent_token"
}
Commission is recorded on receipt. commissionStatus: "approved" reflects immediate recording — no manual review gate.
Error codes:
| Code | Meaning |
|---|---|
400 | Missing required fields |
401 | Invalid Bearer token or slat_v1 signature failure |
403 | Token mismatch |
404 | Program inactive |
409 | Nonce replay — already recorded, treat as success |
429 | Rate limit exceeded |
Nonce deduplication: 48h TTL per agent key. 409 = already recorded. Generate a fresh token with a new nonce for any genuine retry.
GET /v1/agent/commission
Returns commission balance for an agent key.
Auth: Bearer aff_agent_<identifier>
Response 200:
{
"balance": "38.42",
"pending": "12.00",
"paid": "26.42",
"currency": "USD"
}
ACP Transaction Token
The optional acp_transaction_token field enables cross-pipeline attribution in ACP-compatible runtimes. When your agent runs inside an ACP harness (OpenClaw or compatible), pass the framework-generated transaction token to correlate the attribution event back to the originating agent session across multi-agent pipelines.
Omit if not running inside an ACP harness — no effect on attribution validity. Syndicate Links stores but does not validate this token; validation stays with the ACP runtime.
Merchant and Program Discovery
Today's public program discovery, join flows, and reporting are live and documented at syndicatelinks.co/docs. These operate as a separate interface from the ACP attribution layer above.
Quick Start
1. Register at app.syndicatelinks.co
2. Issue an agent key:
POST /affiliate/keys
Authorization: Bearer ak_live_<account-key>
Content-Type: application/json
{ "type": "agent" }
Returns aff_agent_<identifier> — store in your secret manager.
3. Mint a token at conversion time:
token = mint_slat_token(
agent_key="aff_agent_<identifier>",
order_id="order_7891234"
)
Mint at moment of conversion. 5-minute validity window.
4. POST the attribution event:
import requests
response = requests.post(
"https://api.syndicatelinks.co/v1/track/agent-attribution",
headers={"Authorization": "Bearer aff_agent_<identifier>"},
json={
"attribution_token": token,
"orderId": "order_7891234",
"saleAmount": 149.99,
"currency": "USD"
}
)
# 201 = recorded | 409 = already recorded (treat as success)
5. Check commission:
GET /v1/agent/commission
Authorization: Bearer aff_agent_<identifier>
Design Notes
Client-side token minting: No round-trip to get a token. You control nonce uniqueness; server validates signature on receipt.
Not OAuth: Machine-to-machine. slat_v1 binds the event to the agent key, not a user session.
Stateless: No sessions or refresh cycles to manage. Nonce dedup state is Syndicate Links' responsibility.
Reference
- Dashboard:
app.syndicatelinks.co - Marketplace:
affiliate.syndicatelinks.co - Live API docs:
syndicatelinks.co/docs - Support:
hello@syndicatelinks.co