EEP Specification
Version: 0.1-draft | Status: Pre-Release | License: Apache 2.0
Canonical normative text lives in the main EEP repository at docs/current/SPECIFICATION.md. This page summarizes core protocol behavior for quick navigation; if anything disagrees with that file, the repository wins.
Abstract
The Entity Engagement Protocol (EEP) defines how digital entities publish real-time state change events and how authorized subscribers receive them. It uses three transport layers: state resolution (REST), signal stream (SSE and Webhooks), and network pulse (WebSockets). EEP supports the agentic web, where AI agents participate directly in digital interactions.
1. Terminology
| Term | Definition |
|---|---|
| Entity | Any digital subject with a stable identity and state that can change over time (a person, business, AI agent, or product) |
| Source | The entity or platform originating an event, identified by a DID or URI |
| Publisher | The platform responsible for emitting events on behalf of entities |
| Subscriber | An agent, service, or system that has subscribed to receive events |
| Event | A structured, immutable record of a state change at a specific point in time |
| DID | Decentralized Identifier (W3C standard) for globally identifying entities |
| HMAC | Hash-based Message Authentication Code, used to sign webhook payloads |
2. Architecture Overview
A publisher emits events into an internal bus; subscribers receive them over the signal stream (SSE and webhooks) and optionally over the network pulse (WebSockets). The diagram shows three fan-out paths, not a fourth unnamed channel.
3. Layer 1: State Resolution
State resolution allows agents to discover and read the current state of an entity.
3.1 Entity Resolution Endpoint
GET /:type/:username
Accept: application/json | text/markdown | text/toonA compliant publisher MUST serve at minimum JSON (structured entity profile with capabilities, trust score, DID document) and Markdown (human-readable representation for LLM consumption).
3.2 Required Response Headers
HTTP/1.1 200 OK
Content-Type: application/json
EEP-Version: 0.1
EEP-Entity-DID: did:web:example.com:u:acme-corp
Link: <https://api.example.com/eep/subscribe>; rel="subscribe"; type="application/json"
Link: <https://api.example.com/eep/stream?source=acme-corp>; rel="monitor"
Link: </.well-known/agent.json>; rel="agent-card"3.3 Capability Declaration
{
"eep": {
"version": "0.1",
"endpoint": "https://api.example.com/eep",
"supported_delivery": ["webhook", "sse"],
"supported_event_types": ["com.example.entity.*", "com.example.trust.*"],
"identity": {
"did": "did:web:example.com:u:acme-corp",
"verification_endpoint": "https://api.example.com/did/acme-corp"
},
"gated": true,
"gates_url": "https://api.example.com/eep/gates/did:web:example.com:u:acme-corp",
"commerce": true,
"services_url": "https://api.example.com/eep/services/did:web:example.com:u:acme-corp"
}
}3.4 Gated Access
Entities MAY define gates to restrict access to resources. A gate configuration has entity-defined tiers, each with a list of requirements and a set of access patterns.
Standard Requirement Types
| Type | Description | Proof Needed |
|---|---|---|
credential | W3C Verifiable Credential from a named issuer DID | Encoded VC signed by specified issuer |
identity | Proof of DID ownership (know-your-peer) | Signed challenge from agent's DID key |
agreement | Cryptographic signature over SHA-256 hash of a licence document | EdDSA signature + Verifiable Presentation |
data_request | Quid-pro-quo: agent provides specific claims about itself/owner | Signed VP with W3C DPV purpose declaration |
payment | On-chain micropayment to publisher address | Verified transaction hash from compatible L1/L2 |
combined | AND/OR combination of any of the above | All constituent proofs |
Access Restriction Response (402)
{
"error": "access_restricted",
"resource": "content.papers.full_text",
"current_tier": "public",
"required_tier": "academic",
"unmet_requirements": [
{
"type": "credential",
"resolution_hint": "Verifiable Credential required: AcademicAffiliation"
}
],
"gates_config_url": "https://api.example.com/eep/gates/did:web:example.com:u:alice"
}4. Layer 2: Signal Stream (SSE)
4.1 SSE Endpoint
GET /eep/stream
Authorization: Bearer {API_KEY}
Accept: text/event-stream| Parameter | Type | Required | Description |
|---|---|---|---|
source | string | No | Filter by entity username or DID |
events | string | No | Comma-separated event type filter with wildcard support |
last_event_id | string | No | Resume from this event ID |
4.2 Guaranteed Delivery via Last-Event-ID
A compliant EEP publisher MUST implement event replay. When a subscriber reconnects with the Last-Event-ID header, the server MUST replay all events after that ID, up to a configurable retention window (minimum: 24 hours).
4.3 Heartbeat
The publisher MUST send a comment heartbeat every 15 seconds to detect stale connections:
: heartbeat 2026-02-22T14:30:00Z5. Layer 2: Signal Stream (Webhooks)
5.1 Webhook Subscription
POST /eep/subscribe
Authorization: Bearer {API_KEY}
Content-Type: application/json
{
"source_did": "did:web:example.com:u:acme-corp",
"event_types": ["com.example.entity.updated", "com.example.trust.*"],
"delivery_method": "webhook",
"delivery_url": "https://agent.example.com/hooks/eep",
"delivery_format": "cloudevents/v1.0"
}5.2 Webhook Signature Verification
The webhook-signature header contains an HMAC-SHA256 signature over:
{webhook-id}.{webhook-timestamp}.{raw-body}Receiving platforms MUST use crypto.timingSafeEqual() for constant-time comparison and reject timestamps outside the 60-second replay window.
5.3 Retry Policy
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 5 seconds |
| 3 | 30 seconds |
| 4 | 2 minutes |
| 5 | 15 minutes |
| 6 | 1 hour |
| 7 | 6 hours |
6. Layer 3: Network Pulse (WebSockets)
6.1 Message Format
{
"v": 1,
"type": "entity | a2a | system | chat | commerce",
"action": "specific-action",
"seq": 12345,
"data": {}
}6.2 JWT Re-authentication
Server → Client: { "type": "system", "action": "auth_expiring", "data": { "expires_in": 300 } }
Client → Server: { "type": "system", "action": "auth_refresh", "data": { "token": "new-jwt" } }
Server → Client: { "type": "system", "action": "auth_refreshed", "data": { "expires_at": "..." } }If the client fails to refresh within 60 seconds, the server MUST close with code 4001.
6.3 Chat Messages
| Action | Direction | Description |
|---|---|---|
send | Client → Server | Send a message (max 4096 chars). Persisted and broadcast. |
history | Client → Server | Request message history with cursor-based pagination. |
read | Client → Server | Mark messages as read. |
7. Event Envelope Format
All EEP events MUST be valid CloudEvents v1.0.2 envelopes with EEP-specific extensions:
{
"specversion": "1.0",
"id": "unique-event-id",
"source": "did:web:example.com:u:acme-corp",
"type": "com.example.entity.updated",
"time": "2026-02-22T14:30:00Z",
"datacontenttype": "application/json",
"eep_version": "0.1",
"eep_subscription_id": "sub_01HN3QK7GX",
"eep_trust_score": 87,
"eep_actor_type": "human | agent | system | cron",
"data": {}
}| Attribute | Type | Required | Description |
|---|---|---|---|
eep_version | string | MUST | EEP spec version |
eep_subscription_id | string | SHOULD | Subscription this was delivered to |
eep_trust_score | integer | SHOULD | Entity's trust score at event time |
eep_actor_type | string | SHOULD | Who triggered the event |
8. Event Type Naming Convention
EEP event types follow a reverse-domain dot notation pattern:
{reverse-domain}.{entity-type}.{action}
{reverse-domain}.{entity-type}.{sub-domain}.{action}
Examples:
com.example.entity.updated
com.example.trust.changed
com.example.content.published
com.example.commerce.offerWildcard matching: com.example.entity.* matches all entity events. Only prefix matching is supported.
9. Standard Event Catalog
Entity Lifecycle
| Event Type | Description |
|---|---|
com.example.entity.created | A new entity profile was created |
com.example.entity.updated | One or more profile fields changed |
com.example.entity.deleted | Permanently deleted |
com.example.entity.activated | A deactivated entity was reactivated |
com.example.entity.deactivated | Temporarily deactivated |
Trust and Identity
| Event Type | Description |
|---|---|
com.example.trust.changed | Trust score changed |
com.example.trust.signal.added | A trust signal was recorded |
com.example.identity.verified | Verification completed |
com.example.identity.did_updated | DID document updated |
Commerce and Marketplace
| Event Type | Description |
|---|---|
com.example.commerce.offer | A new price offer was made |
com.example.commerce.counter | A counter-offer was made |
com.example.commerce.accepted | Negotiation accepted |
com.example.commerce.invoiced | Invoice generated |
com.example.commerce.paid | Payment confirmed |
com.example.commerce.completed | Transaction completed |
com.example.service.listed | New service published |
com.example.gate.config_changed | Gate configuration updated |
10. Subscription Lifecycle
- Subscribe —
POST /subscribecreates statepending_verification. - Publisher sends a GET verification challenge to the subscriber's
delivery_url. - Verification outcome:
- Success →
active - Failure →
rejected
- Success →
- While
active: deliver events. After 5 consecutive delivery failures →paused. UsePOST /subscriptions/:id/resumeto return toactive.
11. Authentication and Authorization
EEP uses two complementary authentication mechanisms:
- DID-based cryptographic identity (primary) — agents present a W3C DID and sign gate requirement proofs (Verifiable Credentials, challenge responses, payment hashes). This is the canonical zero-trust auth model.
- API key (convenience) — for simple subscriptions without gate requirements, Bearer token auth is accepted.
// Simple subscription — API key
Authorization: Bearer {API_KEY}
// Gated resource — DID proof in request body
POST /eep/gate/proof
{ "type": "identity", "did": "did:web:agent.example.com", "signature": "..." }Scopes
| Scope | Description |
|---|---|
read:subscriptions | List own subscriptions |
write:subscriptions | Create and manage subscriptions |
read:events | Access the SSE stream |
read:gates | Read gate configurations |
write:gates | Modify gate configurations |
commerce:negotiate | Participate in commerce negotiations |
read:services | Browse service listings |
write:services | Publish and manage service listings |
12. Discovery
Subscribers discover EEP endpoints through three mechanisms:
- HTTP Link header — every entity resolution response includes
Link: <...>; rel="subscribe" - Agent card extension — A2A agent card includes
x-eepextension - Well-known document —
GET /.well-known/eep.jsonreturns platform capabilities
13. Rate Limiting
Publishers MUST enforce rate limits and return standard headers:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1708168200
Retry-After: 120| Action | Limit |
|---|---|
| Subscription creation | 100/day |
| SSE connections | 5 concurrent |
| Webhook deliveries received | 10,000/day |
| Event stream history queries | 60/hour |
14. Conformance Levels
| Level | Requirements |
|---|---|
| Core | Layer 1 (REST state) + Layer 2 SSE. Suitable for read-only publishers, IoT sensors, knowledge bases. |
| Standard | Core + Webhooks + HMAC-SHA256 signing + credential and payment gates + version negotiation. Suitable for B2B data APIs, financial feeds. |
| Full | Standard + Layer 3 WebSockets + commerce state machine + agreement + data_request gates + session persistence + W3C DPV privacy declarations. Suitable for agent commerce, regulated industries. |
15. Service Discovery and Marketplace
Entities MAY publish a service catalog of their offerings.
Service Listing Billing Models
The pricing.model field on a service listing declares how recurring or metered charges work:
| Model | Description |
|---|---|
fixed | One-time flat price |
per_request | Charge per API request |
subscription | Recurring charge with a billing period |
metered | Usage-based billing |
tiered_volume | Volume discounts with tier brackets |
x-* | Custom billing models |
Commerce Price Discovery Modes (Whitepaper §8.4)
Separate from billing models, the commerce state machine supports three price discovery modes that govern how agent and entity reach agreement on price during a WebSocket negotiation:
| Mode | Description |
|---|---|
fixed | Publisher sets a non-negotiable price. Agent accepts or walks away. |
negotiated | Bilateral offer/counter over WebSocket until both sides accept. |
auction | Publisher broadcasts an RFP; agents submit bids; publisher selects winner. |
Commerce Negotiation State Machine
Negotiation
offer → [open] → counter → [countered] → accept → [accepted]
- From
[countered]:reject→[rejected] - From
[open]:expire→[expired]
Fulfillment
[accepted] → invoice → [invoiced] → receipt → [paid] → complete → [completed]
Exception
Any active state → dispute → [disputed]
Terminal states: rejected, expired, completed.