API reference
The telemetry API has two sides: write endpoints for agents and platforms reporting events, and read endpoints for content owners querying their data.
Authentication
All authenticated endpoints use an API key in the X-API-Key header.
There are two key types:
| Key type | Prefix | Use case |
|---|---|---|
| Platform | oat_pk | Agents and platforms writing telemetry events |
| Publisher | oat_pub | Content owners querying their own telemetry data |
curl -H "X-API-Key: oat_pub_..." https://api.openattribution.org/api/v1/telemetry/publisher/summaryPublisher keys are scoped to specific domains. A key for wirecutter.com can only query data for that domain. No cross-publisher aggregation.
Base URL
| Environment | URL |
|---|---|
| Production | https://api.openattribution.org/api/v1/telemetry |
| Local development | http://localhost:8007/api/v1/telemetry |
All endpoint paths below are relative to the base URL.
Publisher endpoints
Query telemetry data for your verified domains. Requires a publisher API key.
Summary
GET /publisher/summaryAggregate metrics across your domains - total events, total sessions, breakdown by event type, and per-agent activity.
| Parameter | Type | Description |
|---|---|---|
since | ISO 8601 | Start of period (optional) |
until | ISO 8601 | End of period (optional) |
domain | string | Filter to a specific domain (optional) |
{
"publisher_id": "...",
"publisher_name": "Wirecutter",
"domains": ["wirecutter.com"],
"total_events": 14720,
"total_sessions": 3891,
"events_by_type": [
{ "event_type": "content_retrieved", "count": 14720 }
],
"agents": [
{ "platform_id": "openai", "agent_id": "chatgpt-browse", "event_count": 6200, "session_count": 1580 },
{ "platform_id": "anthropic", "agent_id": "claude-web", "event_count": 4100, "session_count": 1020 },
{ "platform_id": "perplexity", "agent_id": "perplexity", "event_count": 4420, "session_count": 1291 }
],
"period_start": "2026-03-01T00:00:00Z",
"period_end": null
}Events
GET /publisher/eventsPaginated list of individual events for your domains.
| Parameter | Type | Description |
|---|---|---|
since | ISO 8601 | Start of period (optional) |
until | ISO 8601 | End of period (optional) |
domain | string | Filter to a specific domain (optional) |
limit | integer | Page size (default: 100) |
offset | integer | Offset for pagination (default: 0) |
{
"items": [
{
"event_id": "550e8400-...",
"session_id": "7c9e6679-...",
"event_type": "content_retrieved",
"content_url": "https://wirecutter.com/reviews/best-headphones",
"event_timestamp": "2026-03-18T10:00:00Z",
"event_data": { "user_agent": "ClaudeBot/1.0" },
"platform_id": "anthropic",
"agent_id": "claude-web"
}
],
"total": 14720,
"limit": 100,
"offset": 0
}URLs
GET /publisher/urlsPer-URL metrics - which content is being retrieved most, by how many sessions, and when it was last seen.
| Parameter | Type | Description |
|---|---|---|
since, until, domain | - | Same as above |
limit, offset | integer | Pagination (default: limit 20, offset 0) |
{
"items": [
{
"content_url": "https://wirecutter.com/reviews/best-headphones",
"total_events": 842,
"unique_sessions": 391,
"event_types": [
{ "event_type": "content_retrieved", "count": 842 }
],
"last_seen": "2026-03-18T14:22:00Z"
}
],
"total": 156,
"limit": 20,
"offset": 0
}Delegated access
Content owners can grant measurement partners (affiliate networks, dashboard tools, analytics
platforms) read access to their telemetry data. Partners query the same publisher endpoints,
adding the delegated_from parameter.
Querying as a delegate
Append delegated_from to any publisher GET endpoint with the content owner's organisation ID:
GET /publisher/summary?delegated_from={grantor_org_id}&since=2026-03-01The gateway checks for an active delegation from the content owner to your organisation. If
valid, you receive their telemetry data exactly as they would see it. If not, you get a 403.
Managing delegations
Content owners manage delegations via the identity API:
| Endpoint | Description |
|---|---|
GET /identity/delegations | List active delegations. Optional ?role=grantor|grantee |
POST /identity/delegations | Grant access to a partner. Body: grantee_org_id, optional scopes |
DELETE /identity/delegations/{id} | Revoke a delegation. Only the content owner (grantor) can revoke. |
Click tokens
When an agent generates an outbound link, it can create a click token that ties the click back to the full session - which content was retrieved, cited, and by which agent.
Create a click token
POST /click-tokensRequires a platform API key.
{
"session_id": "550e8400-e29b-41d4-a716-446655440000",
"content_url": "https://retailer.com/headphones/sony-wh1000xm5"
}{
"token": "ctx_abc123def456",
"session_id": "550e8400-...",
"content_url": "https://retailer.com/headphones/sony-wh1000xm5",
"expires_at": "2026-06-18T10:00:00Z"
}The agent appends the token to the outbound URL:
https://retailer.com/headphones/sony-wh1000xm5?ctx=ctx_abc123def456Look up a click token
GET /ctx/{token}Public endpoint - no authentication required. Networks and retailers capture the ctx parameter from the landing page URL and look up the session context.
{
"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"
]
}Domain resolution
GET /resolve?domain=wirecutter.comCheck whether a domain maps to a registered content owner. No authentication required.
Accepts either a domain or a url parameter (the domain is extracted from the URL).
{
"domain": "wirecutter.com",
"handled": true,
"publisher": {
"id": "...",
"name": "Wirecutter"
}
}If the domain is not registered, handled is false and publisher is null.
Write endpoints
For agents and platforms reporting telemetry. Requires a platform API key.
Start a session
POST /session/start{
"initiator_type": "user",
"agent_id": "shopping-assistant",
"external_session_id": "ext-123",
"prior_session_ids": ["previous-session-uuid"]
}{
"session_id": "550e8400-e29b-41d4-a716-446655440000"
}| Field | Required | Description |
|---|---|---|
initiator_type | No | "user" or "agent" (default: "user") |
agent_id | No | Identifier for the responding agent |
manifest_ref | No | AIMS manifest reference for the agent |
content_scope | No | Opaque identifier for content access context |
external_session_id | No | Your own session identifier |
prior_session_ids | No | Previous session UUIDs for multi-session attribution |
Record events
POST /events{
"session_id": "550e8400-...",
"events": [
{
"id": "event-uuid-1",
"type": "content_retrieved",
"timestamp": "2026-03-18T10:00:00Z",
"source_role": "agent",
"content_url": "https://wirecutter.com/reviews/best-headphones",
"oa_telemetry_id": "telemetry-correlation-uuid"
},
{
"id": "event-uuid-2",
"type": "content_cited",
"timestamp": "2026-03-18T10:00:05Z",
"source_role": "agent",
"content_url": "https://wirecutter.com/reviews/best-headphones"
}
]
}{
"status": "ok",
"events_created": 2
}End a session
POST /session/end{
"session_id": "550e8400-...",
"outcome": {
"type": "conversion",
"value_amount": 34900,
"currency": "USD"
}
}The value_amount is in minor currency units (cents for USD). Outcome types: "conversion", "abandonment", "browse".
Bulk session upload
POST /session/bulkUpload a complete session - start, events, and outcome - in a single request. Useful for batch reporting or replaying historical data.
{
"session_id": "550e8400-...",
"agent_id": "shopping-assistant",
"started_at": "2026-03-18T10:00:00Z",
"ended_at": "2026-03-18T10:05:00Z",
"events": [
{
"id": "event-uuid-1",
"type": "content_retrieved",
"timestamp": "2026-03-18T10:00:00Z",
"source_role": "agent",
"content_url": "https://wirecutter.com/reviews/best-headphones"
}
],
"outcome": {
"type": "conversion",
"value_amount": 34900,
"currency": "USD"
}
}{
"session_id": "550e8400-...",
"events_created": 1,
"outcome_recorded": true
}Event types
| Type | When | Source role |
|---|---|---|
content_retrieved | Content fetched from source | origin, edge, index, or agent |
content_cited | Content referenced in an agent's response | agent |
content_displayed | Content shown to user in a card or sidebar | agent |
content_engaged | User interacted with cited content | agent |
turn_started | User initiated a conversation turn | agent |
turn_completed | Agent finished responding | agent |
checkout_completed | Purchase completed with value | agent |
Source roles
The source_role field identifies who is reporting the event. Multiple observers can report the same retrieval from
different vantage points.
| Role | Reporter |
|---|---|
origin | Content owner's web server (e.g. WordPress plugin) |
edge | CDN or edge network (Cloudflare, Fastly, etc.) |
index | Content marketplace or licensed content repository |
agent | The AI agent itself |
Health
| Endpoint | Auth | Purpose |
|---|---|---|
GET /health | None | Returns {"status": "ok"} |
GET /ready | None | Database connectivity check |