Skip to content

Feedback Data Profile

Description

Recommended offchain data profile for ERC-8004 feedback records

This document provides implementation-agnostic guidance for structuring feedback data referenced by the feedbackURI field in ERC-8004 Reputation Registry contracts.

Version Info: This document describes the v1.1 specification (January 2026). For pre-v1 legacy documentation, see archive copy.

Document Purpose

This profile document offers practical, non-normative recommendations for feedback data formats used with ERC-8004 Reputation Registries, based on real-world usage patterns and community feedback.

Relationship to EIP-8004

Important: This is not part of the official EIP-8004 specification.

Official EIP-8004 defines:

  • Reputation Registry smart contract interface
  • Onchain fields: score, tag1, tag2, endpoint, feedbackURI, feedbackHash
  • The feedbackURI field is OPTIONAL

This profile suggests:

  • Offchain JSON structure for feedback data
  • Protocol-specific field patterns (A2A, MCP)
  • Evidence attachment guidelines
  • Payment proof integration (x402)

The official EIP makes feedbackURI optional. When provided, this profile recommends patterns for its content.

Key Changes in v1.1 (January 2026)

Fieldpre-v1 (legacy)v1.1
Tag Typesbytes32string
URI NamingfeedbackUrifeedbackURI
FeedbackAuthRequiredRemoved
EndpointNEW
feedbackIndexCalculatedFrom event

See migration guide for upgrading from pre-v1 (legacy).

Terminology

This document follows conventions defined in Conventions. For attachment file patterns, see Attachment Pattern Standard.

Intended Audience

  • Service clients giving feedback
  • Registry implementers building indexers and explorers

Table of Contents

  1. Overview
  2. Recommended Feedback Profile
  3. Attachment Pattern
  4. Protocol-Specific Fields
  5. Payment Proof Integration
  6. Authorization (Deprecated)
  7. Examples
  8. Best Practices

Overview

Onchain vs Offchain Data

Onchain (Reputation Registry contract):

  • score (uint8, 0-100) - REQUIRED
  • tag1, tag2 (string) - OPTIONAL (now direct strings, no encoding)
  • endpoint (string) - OPTIONAL, specifies the service endpoint
  • feedbackURI (string) - OPTIONAL
  • feedbackHash (bytes32) - OPTIONAL
  • feedbackIndex (uint64) - From event emission (no longer calculated)

Onchain Events (for indexers):

  • NewFeedback: agentId (indexed), clientAddress (indexed), feedbackIndex, score, indexedTag1 (indexed), tag1, tag2, endpoint, feedbackURI, feedbackHash
  • FeedbackRevoked: agentId (indexed), clientAddress (indexed), feedbackIndex (indexed)
  • ResponseAppended: agentId (indexed), clientAddress (indexed), feedbackIndex, responder (indexed), responseURI, responseHash

Note for Indexers: The indexed parameters can be efficiently filtered in event queries. Non-indexed parameters require full log scanning.

Important (v1.1.1 update): tag1 is now emitted twice in NewFeedback:

  • indexedTag1 (indexed): Topic-hashed for efficient filtering
  • tag1 (non-indexed): Actual string value for direct access

This allows both efficient filtering AND direct value retrieval without decoding.

Offchain (referenced by feedbackUri):

  • Detailed feedback context and reasoning
  • Proof of payment (x402 protocol)
  • Protocol-specific fields (A2A/MCP)
  • Evidence attachments
  • Custom extensions

Non-normative: The feedbackUri field is optional per EIP-8004. However, providing rich offchain data improves trust, transparency, and enables better discovery and dispute resolution.

Suggested Schema

jsonc
{
  // ============ MUST FIELDS (per official spec) ============
  "agentRegistry": "eip155:84532:0x8004C269D0A5647E51E121FeB226200ECE932d55",
  "agentId": 22,
  "clientAddress": "eip155:84532:0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
  "createdAt": "2025-12-20T12:00:00Z",
  "score": 100,

  // ============ ALL OPTIONAL FIELDS (per official spec) ============
  "tag1": "defi",
  "tag2": "analytics",
  "endpoint": "https://api.agent.example.com/v1",

  // A2A / OASF fields
  "skill": "analytical_skills/data_analysis",  // as-defined-by-A2A-or-OASF
  "domain": "technology/blockchain",            // as-defined-by-OASF (NEW in v1.1)
  "context": "Analyzed blockchain transaction data for portfolio optimization",
  "task": "Generate daily analytics report with recommendations",

  // MCP fields
  "capability": "tools",  // prompts, resources, tools, or completions
  "name": "blockchain_analyzer",

  // x402 payment proof
  "proofOfPayment": {
    "fromAddress": "0x742d35Cc...",
    "toAddress": "0x8004...",
    "chainId": "84532",
    "txHash": "0xabc123..."
  },

  // ============ BEST PRACTICES EXTENSIONS (this profile) ============
  "reasoning": "Excellent portfolio analysis service.",
  "attachments": [
    {
      "name": "Service Receipt",
      "uri": "ipfs://QmXxx...",
      "mimeType": "application/pdf",
      "size": 50000
    }
  ],

  // Other custom fields
  " ... ": { " ... " }
}

NOTE

This schema follows the official EIP-8004 spec structure. Fields marked "MUST" are required by the spec; fields marked "OPTIONAL" are defined by the spec but not required. "Best Practices Extensions" are additional recommendations from this profile.

The feedbackAuth field has been removed in v1.1. Feedback no longer requires pre-authorization from agents. See migration guide for details.

FieldTypeConstraintsDescription
agentRegistrystringCAIP-10 formatAgent's identity registry address
agentIdnumberuint256, ≥ 0Agent token ID
clientAddressstringCAIP-10 formatClient's wallet address
createdAtstringISO 8601 UTCFeedback creation timestamp
scorenumber0–100 inclusive (uint8 onchain)Overall feedback score (must match onchain value)

CAIP Format References:

  • CAIP-10 (Contract Address): eip155:84532:0x8004C269...Conventions
  • CAIP-10 (Account ID): eip155:84532:0x742d35Cc...Conventions
FieldTypeDescription
reasoningstringHuman-readable explanation of the feedback score
tag1stringPrimary category tag (direct string, not encoded)
tag2stringSecondary category tag (direct string)
endpointstringService endpoint used for interaction (NEW in v1.1)

Note: In v1.1, tag1 and tag2 are direct strings on-chain. No encoding/decoding needed. The endpoint field is optional but recommended for tracking which specific service endpoint was used.

Attachment Pattern

Overview

The attachment pattern allows clients to provide evidence, receipts, or supporting documents with their feedback.

For complete attachment schema and guidelines, see Attachment Pattern Guidelines.

Quick Reference

Attachments use the following structure:

typescript
interface AttachmentFile {
  name: string; // Display name (required)
  uri: string; // File location (required)
  mimeType: string; // MIME type (required)
  size: number; // File size in bytes (required)
  description?: string; // Optional context
  uploadedAt?: string; // Optional timestamp (ISO 8601 UTC)
}

Example:

json
{
  "attachments": [
    {
      "name": "Service Receipt",
      "uri": "ipfs://QmXxx...",
      "mimeType": "application/pdf",
      "size": 50000,
      "description": "Invoice and deliverables",
      "uploadedAt": "2025-12-20T15:00:00Z"
    }
  ]
}

Common Use Cases

1. Service Receipts: Proof of service completion
2. Communication Logs: Chat transcripts showing responsiveness
3. Work Product: Deliverables and analysis reports
4. Screenshots: Visual evidence of results

Supported File Types: PDFs, images, videos, JSON, CSV, text files, and more.

See Attachment Pattern Guidelines for:

  • Detailed field specifications
  • Security considerations
  • Best practices
  • Implementation requirements
json
{
  "name": "Analysis Report",
  "uri": "ipfs://QmZzz...",
  "mimeType": "application/pdf",
  "description": "Final deliverable - 50-page portfolio analysis report"
}

4. Screenshots/Evidence

json
{
  "name": "Service Screenshot",
  "uri": "ipfs://QmAaa...",
  "mimeType": "image/png",
  "description": "Screenshot showing successful task completion at 10:45 UTC"
}

Supported File Types

  • ✅ Documents: PDF, Word, Markdown, Text
  • ✅ Images: PNG, JPEG, WebP, GIF
  • ✅ Data: JSON, CSV, XML
  • ✅ Archives: ZIP (for multiple files)
  • ✅ Any other format (stored as-is)

Protocol-Specific Fields

A2A / OASF Protocol Fields

For feedback on Agent-to-Agent (A2A) interactions or OASF taxonomy:

FieldTypeExampleDescription
skillstring"analytical_skills/data_analysis"A2A or OASF skill taxonomy
domainstring"technology/blockchain"OASF domain taxonomy (NEW)
contextstring"Analyzed blockchain data"Task context (A2A)
taskstring"Generate analytics report"Specific task (A2A)

NOTE

v1.1 Change: The skill field now accepts both A2A and OASF skill slugs. The domain field was added for OASF domain taxonomy.

Taxonomy References:

MCP Protocol Fields

For feedback on Model Context Protocol (MCP) capabilities:

FieldTypeValuesDescription
capabilitystringprompts, resources, tools, completionsMCP capability type
namestring"blockchain_analyzer"Name of the tool/resource/prompt

Custom Extensions

The standard supports arbitrary custom fields:

json
{
  "score": 95,
  // ... standard fields ...

  // Custom breakdown
  "rating_breakdown": {
    "speed": 95,
    "accuracy": 100,
    "communication": 90
  },

  // Custom identifiers
  "interaction_id": "uuid-v4",
  "session_id": "session-123",

  // Custom metadata
  "service_duration_hours": 2.5,
  "revisions_requested": 1
}

Payment Proof Integration

x402 Protocol Support

NOTE

v1.1 Change: The field name changed from proof_of_payment (snake_case) to proofOfPayment (camelCase) in January 2026 for JSON naming consistency.

The proofOfPayment field integrates with the x402 payment protocol for agents.

typescript
// Official EIP-8004 spec fields
interface ProofOfPayment {
  fromAddress: string; // Payer address (0x...)
  toAddress: string; // Payee address (0x...)
  chainId: string; // Chain ID as string (e.g., "1", "84532")
  txHash: string; // Transaction hash (0x...)

  // Best practices extensions (this profile)
  amount?: string; // Payment amount (wei/smallest unit)
  currency?: string; // Currency symbol (e.g., "ETH", "USDC")
  protocol?: string; // Payment protocol (e.g., "x402")
  timestamp?: string; // Payment timestamp (ISO 8601)
}

Example: ETH Payment

json
{
  "proofOfPayment": {
    "fromAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
    "toAddress": "0x8004C269D0A5647E51E121FeB226200ECE932d55",
    "chainId": "84532",
    "txHash": "0xabc123..."
  }
}

Example: ETH Payment with Extensions

json
{
  "proofOfPayment": {
    "fromAddress": "0x742d35Cc...",
    "toAddress": "0x8004...",
    "chainId": "84532",
    "txHash": "0xabc123...",
    "amount": "100000000000000000",
    "currency": "ETH",
    "protocol": "x402"
  }
}

Authorization (Deprecated in v1.1)

⚠️ DEPRECATED: The feedbackAuth field and pre-authorization flow have been removed in v1.1.

In pre-v1 (legacy), feedback required cryptographic authorization from agents. In v1.1, anyone can submit feedback directly without pre-approval. Spam/Sybil protection now relies on off-chain filtering and reputation scoring.

See migration guide if you're upgrading from pre-v1 (legacy).

Examples

Example 1: Simple Feedback

json
{
  "agentRegistry": "eip155:84532:0x8004C269D0A5647E51E121FeB226200ECE932d55",
  "agentId": 22,
  "clientAddress": "eip155:84532:0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
  "createdAt": "2025-12-20T12:00:00Z",
  "score": 95,

  "reasoning": "Great DeFi analytics agent. Quick response time and accurate insights.",
  "tag1": "defi",
  "tag2": "analytics",
  "endpoint": "https://api.example.com/analytics/v1"
}

Example 2: Detailed A2A Feedback with Payment Proof

json
{
  "agentRegistry": "eip155:84532:0x8004C269D0A5647E51E121FeB226200ECE932d55",
  "agentId": 45,
  "clientAddress": "eip155:84532:0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
  "createdAt": "2025-12-20T14:30:00Z",
  "score": 100,

  "reasoning": "Exceptional market analysis service. Provided comprehensive report with actionable insights.",
  "tag1": "trading",
  "tag2": "research",

  "skill": "analytical_skills/market_analysis",
  "context": "Analyzed crypto market trends for Q4 2025",
  "task": "Generate comprehensive market analysis report with predictions",

  "proofOfPayment": {
    "fromAddress": "eip155:84532:0x742d35Cc...",
    "toAddress": "eip155:84532:0x8004...",
    "chainId": 84532,
    "txHash": "0x789abc...",
    "amount": "500000000000000000",
    "currency": "ETH",
    "protocol": "x402"
  },

  "attachments": [
    {
      "name": "Market Analysis Report",
      "uri": "ipfs://QmXxx...",
      "mimeType": "application/pdf",
      "size": 2048000,
      "description": "75-page comprehensive market analysis with charts and predictions",
      "uploadedAt": "2025-12-20T14:00:00Z"
    },
    {
      "name": "Raw Data",
      "uri": "ipfs://QmYyy...",
      "mimeType": "text/csv",
      "size": 500000,
      "description": "Historical price data used for analysis",
      "uploadedAt": "2025-12-20T14:00:00Z"
    }
  ],

  "rating_breakdown": {
    "depth": 100,
    "accuracy": 100,
    "timeliness": 95,
    "presentation": 100
  },
  "interaction_id": "550e8400-e29b-41d4-a716-446655440000"
}

Example 3: MCP Tool Feedback

json
{
  "agentRegistry": "eip155:11155111:0x8004...",
  "agentId": 78,
  "clientAddress": "eip155:11155111:0x123...",
  "createdAt": "2025-12-20T16:00:00Z",
  "score": 90,

  "reasoning": "Blockchain analyzer MCP tool worked well. Accurate transaction parsing.",
  "tag1": "mcp",
  "tag2": "tools",

  "capability": "tools",
  "name": "blockchain_transaction_parser",

  "rating_breakdown": {
    "accuracy": 95,
    "speed": 85,
    "reliability": 90
  }
}

Best Practices

1. Always Provide Reasoning

❌ Bad:

json
{
  "score": 80
}

✅ Good:

json
{
  "score": 80,
  "reasoning": "Good service overall. Response time was a bit slow (2 hours), but final deliverable quality was excellent."
}

2. Include Evidence for Disputes

For high-stakes or high-value interactions, include attachments:

json
{
  "score": 100,
  "reasoning": "...",
  "attachments": [
    {
      "name": "Service Receipt",
      "uri": "ipfs://...",
      "mimeType": "application/pdf",
      "description": "Official receipt showing completed deliverables"
    }
  ]
}

3. Use Protocol-Specific Fields

If using A2A, OASF, or MCP, include relevant fields for better discoverability:

A2A / OASF Example:

json
{
  "score": 95,
  "tag1": "defi",
  "tag2": "analytics",
  "skill": "analytical_skills/data_analysis/blockchain_analysis",
  "domain": "technology/blockchain",
  "context": "Analyzed blockchain transaction patterns for portfolio optimization"
}

MCP Example:

json
{
  "score": 90,
  "tag1": "mcp",
  "tag2": "tools",
  "capability": "tools",
  "name": "blockchain_analyzer",
  "context": "Used MCP tools capability for blockchain data analysis"
}

4. Include Payment Proof for x402

For agents supporting x402 payment protocol:

json
{
  "score": 100,
  "proofOfPayment": {
    "txHash": "0x...",
    "amount": "100000000000000000",
    "currency": "ETH"
  }
}

5. Use CAIP Formats for Addresses

❌ Bad:

json
{
  "clientAddress": "0x742d35Cc..."
}

✅ Good:

json
{
  "clientAddress": "eip155:84532:0x742d35Cc..."
}

6. Include Endpoint Information (v1.1)

NEW in v1.1: Always include the endpoint field to track which service endpoint was used:

❌ Missing context:

json
{
  "score": 95,
  "tag1": "defi"
}

✅ Good - with endpoint:

json
{
  "score": 95,
  "tag1": "defi",
  "endpoint": "https://api.agent.example.com/v1",
  "reasoning": "Used the v1 API endpoint. Fast response and accurate results."
}

This helps distinguish feedback for different versions or deployments of the same agent.

7. Use String Tags Directly (v1.1)

NEW in v1.1: Tags are now direct strings, not encoded bytes32:

❌ Old pre-v1 format (deprecated):

json
{
  "tag1": "6465666900000000000000000000000000000000000000000000000000000000",
  "tag2": "616e616c7974696373000000000000000000000000000000000000000000000000"
}

✅ v1.1 format:

json
{
  "tag1": "defi",
  "tag2": "analytics"
}

8. Timestamp Everything

json
{
  "createdAt": "2025-12-20T12:00:00Z",
  "proofOfPayment": {
    "timestamp": "2025-12-20T11:45:00Z"
  },
  "attachments": [
    {
      "uploadedAt": "2025-12-20T11:50:00Z"
    }
  ]
}

9. Complete v1.1 Best Practice Example

Here's a comprehensive example following all v1.1 best practices:

json
{
  // Core required fields
  "agentRegistry": "eip155:84532:0x8004C269D0A5647E51E121FeB226200ECE932d55",
  "agentId": 22,
  "clientAddress": "eip155:84532:0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
  "createdAt": "2025-12-20T12:00:00Z",
  "score": 95,

  // v1.1 fields (string tags + endpoint)
  "tag1": "defi",
  "tag2": "analytics",
  "endpoint": "https://api.agent.example.com/v2",

  // Human context
  "reasoning": "Excellent DeFi analytics service. Used the v2 API which provided faster response times. The portfolio optimization recommendations were accurate and well-explained.",

  // Protocol-specific fields (OASF)
  "skill": "analytical_skills/data_analysis/blockchain_analysis",
  "domain": "finance_and_business/finance",
  "context": "Portfolio optimization for DeFi positions across multiple chains",

  // Payment proof (x402)
  "proofOfPayment": {
    "fromAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb",
    "toAddress": "0x8004C269D0A5647E51E121FeB226200ECE932d55",
    "chainId": "84532",
    "txHash": "0xabc123...",
    "amount": "100000000000000000",
    "currency": "ETH",
    "timestamp": "2025-12-20T11:45:00Z"
  },

  // Evidence attachments
  "attachments": [
    {
      "name": "Analysis Report",
      "uri": "ipfs://QmXxx...",
      "mimeType": "application/pdf",
      "size": 250000,
      "description": "Full 50-page portfolio analysis with recommendations",
      "uploadedAt": "2025-12-20T11:50:00Z"
    },
    {
      "name": "Service Receipt",
      "uri": "ipfs://QmYyy...",
      "mimeType": "application/pdf",
      "size": 50000,
      "description": "Invoice and proof of deliverables",
      "uploadedAt": "2025-12-20T11:55:00Z"
    }
  ]
}

Why this example follows best practices:

  • ✅ Uses CAIP-10 format for addresses
  • ✅ Includes endpoint to track API version used
  • ✅ Uses direct string tags (not hex-encoded)
  • ✅ Provides detailed reasoning
  • ✅ Includes protocol-specific fields (skill, domain)
  • ✅ Has payment proof with full details
  • ✅ Includes evidence attachments
  • ✅ All timestamps in ISO 8601 UTC format
  • ✅ No feedbackAuth field (removed in v1.1)

FAQ

Q: How do I handle feedback revocation or deletion?

A: Use the FeedbackRevoked event to mark feedback as deleted (immutability-safe approach):

solidity
// From ReputationRegistry.sol
event FeedbackRevoked(
    uint256 indexed agentId,
    address indexed clientAddress,
    uint64 indexed feedbackIndex
);

// Client can revoke their own feedback
function revokeFeedback(uint256 agentId, uint64 feedbackIndex) external {
    // Only the client who submitted feedback can revoke it
    require(msg.sender == feedbackClients[agentId][feedbackIndex],
            "Only feedback author can revoke");

    emit FeedbackRevoked(agentId, msg.sender, feedbackIndex);
}

Indexer handling:

  • Track FeedbackRevoked events
  • Mark feedback as deleted (don't remove it)
  • Exclude revoked feedback from reputation calculations
  • Show revocation status in UI ("This feedback was revoked")

Off-chain data: Archive revoked feedback but don't delete URIs (preserves immutability)


Q: How do I efficiently index and search large feedback volumes?

A: Leverage the indexed event parameters for optimized queries:

solidity
event NewFeedback(
    uint256 indexed agentId,        // ← Query by agent
    address indexed clientAddress,  // ← Query by reviewer
    uint64 feedbackIndex,           // ← Sequential ordering
    uint8 score,
    string indexed indexedTag1,     // ← Filter by tag efficiently (topic hash)
    string tag1,                    // ← Actual tag1 value (v1.1.1+)
    string tag2,
    string endpoint,
    string feedbackURI,
    bytes32 feedbackHash
);

Optimization strategies:

  1. Use indexed parameters in queries:

    typescript
    // Efficient: Uses event indexes
    const agentFeedback = await contract.queryFilter(
      contract.filters.NewFeedback(agentId, null, null, null, null)
    );
    
    // Also efficient: Filter by tag
    const defiFeedback = await contract.queryFilter(
      contract.filters.NewFeedback(null, null, null, null, "defi")
    );
  2. Aggregate in time windows: Don't recalculate entire reputation on every query

    • Cache score averages per (agentId, tag) per time period
    • Incrementally update on new feedback
  3. Use feedbackIndex for pagination:

    typescript
    // Get feedback 100-200 for (agent, client)
    const feedback = await db.query(
      "SELECT * FROM feedback WHERE agentId = ? AND feedbackIndex BETWEEN ? AND ?",
      [agentId, 100, 200]
    );
  4. Separate hot/cold data:

    • Hot: Recent feedback (last 30 days) → fast index
    • Cold: Historical feedback → compressed archive

See Also

Official EIP-8004 Specification: https://eips.ethereum.org/EIPS/eip-8004