|

Agent integration

When your agent fetches content from the web and uses it in a response, OpenAttribution tracks that usage so content owners get visibility. This page explains what to report, when, and how.


The short version

Your agent does two things that matter for attribution:

  1. Retrieves content - fetches a URL to read it
  2. Cites content - uses that content in a response to the user

Report both. Retrieval alone tells the publisher their content was accessed. Citation tells them it was actually used. The combination is what makes attribution meaningful.


Setup

1. Get an API key

Register your agent to get a platform API key. This key authenticates your telemetry submissions.

2. Discover the telemetry endpoint

Before fetching content from a domain, check for a /.well-known/openattribution file. If it exists, it tells you where to send telemetry for that domain.

bash
curl -s https://example.com/.well-known/openattribution | jq .
response
{
  "openattribution": {
    "version": "0.1",
    "telemetry_endpoint": "https://api.openattribution.org/api/v1/telemetry",
    "verification": "oa-verify=..."
  }
}

The telemetry_endpoint is where you send events. For most publishers this points to OA's server, but some may self-host.

Cache the lookup
The well-known file changes rarely. Cache it per domain for at least an hour to avoid unnecessary requests.

Reporting events

A typical agent interaction produces this sequence:

event flow
User asks a question
  -> Agent fetches content          (content_retrieved)
  -> Agent generates response       (content_cited)
  -> User sees response             (content_displayed)
  -> User clicks a source link      (content_engaged)

You can report events incrementally during a session or upload a complete session at the end. Both patterns are supported.

Option A: Incremental reporting

Start a session, report events as they happen, end the session.

1. Start session
curl -X POST https://api.openattribution.org/api/v1/telemetry/session/start \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "initiator_type": "user",
    "agent_id": "your-agent-name"
  }'
response
{ "session_id": "550e8400-e29b-41d4-a716-446655440000" }
2. Report events
curl -X POST https://api.openattribution.org/api/v1/telemetry/events \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "550e8400-e29b-41d4-a716-446655440000",
    "events": [
      {
        "type": "content_retrieved",
        "timestamp": "2026-03-18T10:00:01Z",
        "source_role": "agent",
        "content_url": "https://example.com/article/best-headphones"
      },
      {
        "type": "content_cited",
        "timestamp": "2026-03-18T10:00:05Z",
        "source_role": "agent",
        "content_url": "https://example.com/article/best-headphones",
        "data": {
          "citation_type": "paraphrase",
          "excerpt_tokens": 85,
          "excerpt_chars": 340,
          "position": "primary",
          "media_type": "text"
        }
      }
    ]
  }'
3. End session
curl -X POST https://api.openattribution.org/api/v1/telemetry/session/end \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "550e8400-e29b-41d4-a716-446655440000",
    "outcome": { "type": "browse" }
  }'

Option B: Bulk upload

Upload a complete session after it ends. Simpler if you're batch processing.

bash
curl -X POST https://api.openattribution.org/api/v1/telemetry/session/bulk \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "agent_id": "your-agent-name",
    "started_at": "2026-03-18T10:00:00Z",
    "ended_at": "2026-03-18T10:05:00Z",
    "events": [
      {
        "type": "content_retrieved",
        "timestamp": "2026-03-18T10:00:01Z",
        "source_role": "agent",
        "content_url": "https://example.com/article/best-headphones"
      },
      {
        "type": "content_cited",
        "timestamp": "2026-03-18T10:00:05Z",
        "source_role": "agent",
        "content_url": "https://example.com/article/best-headphones",
        "data": {
          "citation_type": "paraphrase",
          "excerpt_tokens": 85,
          "position": "primary"
        }
      }
    ],
    "outcome": { "type": "browse" }
  }'

Event types

These are the events an agent typically reports. All use source_role: "agent".

content_retrieved

Your agent fetched a URL. Report this for every URL you read, whether or not you end up using it. This is the base signal - it tells publishers their content was accessed.

FieldRequiredDescription
content_urlYesThe URL you fetched
data.media_typeNotext, image, video, or audio. Defaults to text

content_cited

Your agent used the content in its response. This is the high-value signal - it connects retrieval to actual use.

FieldRequiredDescription
content_urlYesThe URL you cited
data.citation_typeNodirect_quote, paraphrase, reference, or contradiction
data.excerpt_tokensNoToken count of the excerpt used
data.excerpt_charsNoCharacter count of the excerpt used
data.positionNoprimary, supporting, or mentioned
data.media_typeNotext, image, video, or audio
data.content_hashNoSHA-256 of the content you processed (sha256:{hex}). Useful for dispute resolution

content_displayed

Content was shown to the user - in a card, sidebar, source list, or inline citation. Not all agents have a display surface, so this is optional.

content_engaged

The user interacted with cited content. The data.engagement_type field captures what happened:

engagement_typeWhen to send
link_clickUser clicked a link to the source content
expandUser expanded a citation preview or source card
copyUser copied the cited text
shareUser shared the response or a specific citation

Click tokens and landing page attribution

When your agent displays a link to source content and the user clicks it, you can pass session context through to the landing page. This lets the destination site (or their affiliate network) see which content influenced the visit - closing the loop between "agent cited this article" and "user landed here."

How it works

  1. Before displaying an outbound link, create a click token for the session
  2. Append the token to the URL as a ctx query parameter
  3. When the user clicks, report a content_engaged event with link_click
  4. The landing page owner captures ctx and looks up the session via the public API
1. Create a click token
curl -X POST https://api.openattribution.org/api/v1/telemetry/click-tokens \
  -H "X-API-Key: YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "session_id": "550e8400-e29b-41d4-a716-446655440000",
    "content_url": "https://retailer.com/headphones/sony-wh1000xm5"
  }'
response
{
  "token": "ctx_abc123def456",
  "session_id": "550e8400-...",
  "content_url": "https://retailer.com/headphones/sony-wh1000xm5",
  "expires_at": "2026-06-18T10:00:00Z"
}

Append the token to the outbound URL:

text
https://retailer.com/headphones/sony-wh1000xm5?ctx=ctx_abc123def456

The landing page owner (or their network) captures the ctx parameter and looks up the session context:

lookup (no auth required)
curl https://api.openattribution.org/api/v1/telemetry/ctx/ctx_abc123def456
response
{
  "session_id": "550e8400-...",
  "started_at": "2026-03-18T10:00:00Z",
  "click_content_url": "https://retailer.com/headphones/sony-wh1000xm5",
  "content_urls_cited": [
    "https://wirecutter.com/reviews/best-headphones",
    "https://techradar.com/best/wireless-headphones"
  ],
  "content_urls_retrieved": [
    "https://wirecutter.com/reviews/best-headphones",
    "https://techradar.com/best/wireless-headphones",
    "https://rtings.com/headphones/reviews/sony/wh-1000xm5"
  ]
}
Privacy controls
Session context is only available via click token lookup when two conditions are met: the agent has enabled click token session sharing in their OA dashboard settings, and the content owners whose URLs appear in the session have enabled click token URL visibility in theirs. Both are single toggles - no per-content-owner approval needed. If either condition is not met, the lookup returns the click URL only - no session context. Tokens expire after 90 days.

Report the click

When the user clicks the link, report a content_engaged event so the publisher sees the clickthrough:

json
{
  "type": "content_engaged",
  "timestamp": "2026-03-18T10:01:00Z",
  "source_role": "agent",
  "content_url": "https://retailer.com/headphones/sony-wh1000xm5",
  "data": {
    "engagement_type": "link_click"
  }
}

The OA-Telemetry-ID header

When your agent fetches content over HTTP, include an OA-Telemetry-ID header with a UUID:

text
GET /article/best-headphones HTTP/1.1
Host: www.example.com
OA-Telemetry-ID: 550e8400-e29b-41d4-a716-446655440000

Then include the same UUID as the oa_telemetry_id field on your content_retrieved event.

This enables cross-observer correlation. If the publisher's CDN or web server also reports the retrieval, both events share the same ID. A retrieval confirmed by both agent and publisher is a stronger signal than either alone.

your event
{
  "type": "content_retrieved",
  "timestamp": "2026-03-18T10:00:01Z",
  "source_role": "agent",
  "oa_telemetry_id": "550e8400-e29b-41d4-a716-446655440000",
  "content_url": "https://www.example.com/article/best-headphones"
}
Not required, but valuable
The header is optional. Without it, your retrieval events still work - they just can't be corroborated against the publisher's own logs.

Session outcomes

When you end a session, include an outcome. This closes the attribution loop.

OutcomeWhen
browseUser read the response, no further action
conversionUser completed a purchase or signup
abandonmentUser left mid-conversation

For conversions, include the value:

json
{
  "outcome": {
    "type": "conversion",
    "value_amount": 4999,
    "currency": "USD"
  }
}

value_amount is in minor currency units - cents for USD, pence for GBP. So $49.99 = 4999.


What to report when

Start with retrieval and citation. These two events cover the core attribution signal. Add the rest as your integration matures.

PriorityEventsWhat it enables
Start herecontent_retrieved + content_citedPublishers see which content is being used and how
Add nextcontent_displayed + content_engagedClickthrough rates, engagement metrics
If applicableSession outcomes + OA-Telemetry-ID headerFull attribution loop, cross-observer corroboration

Next steps