diff --git a/packages/@eep-dev/compliance-cli/src/schemas.ts b/packages/@eep-dev/compliance-cli/src/schemas.ts index 7e3314b..06f6f1f 100644 --- a/packages/@eep-dev/compliance-cli/src/schemas.ts +++ b/packages/@eep-dev/compliance-cli/src/schemas.ts @@ -14,7 +14,9 @@ * helper. It is the same wiring as `tests/conformance-fixtures.test.ts`, * lifted into the published package. */ -import Ajv, { type ValidateFunction } from 'ajv'; +// Schemas are JSON Schema 2020-12; Ajv's default export only +// understands draft-07, so the 2020-12 build is required. +import Ajv2020, { type ValidateFunction } from 'ajv/dist/2020.js'; import addFormats from 'ajv-formats'; import { readdirSync, readFileSync, statSync, existsSync } from 'node:fs'; import { join, resolve, dirname } from 'node:path'; @@ -87,7 +89,7 @@ export function loadSchemaRegistry(explicitDir?: string): SchemaRegistry | null const dir = findSchemasDir(explicitDir); if (!dir) return null; - const ajv = new Ajv({ strict: false, allErrors: true, allowUnionTypes: true }); + const ajv = new Ajv2020({ strict: false, allErrors: true, allowUnionTypes: true }); addFormats(ajv); const byFile = new Map(); diff --git a/packages/@eep-dev/gates/src/g-a1-a8.test.ts b/packages/@eep-dev/gates/src/g-a1-a8.test.ts index c1e31c4..17abd5c 100644 --- a/packages/@eep-dev/gates/src/g-a1-a8.test.ts +++ b/packages/@eep-dev/gates/src/g-a1-a8.test.ts @@ -206,23 +206,23 @@ describe('A4 — audit-log.json: delivery audit log schema and SPECIFICATION §1 } }); - it('defines AuditEntry in definitions', () => { - expect(schema.definitions).toHaveProperty('AuditEntry'); + it('defines AuditEntry in $defs', () => { + expect(schema.$defs).toHaveProperty('AuditEntry'); }); it('AuditEntry has all required fields including signature', () => { - const required = schema.definitions.AuditEntry.required as string[]; + const required = schema.$defs.AuditEntry.required as string[]; for (const f of ['entry_id', 'event_type', 'actor_did', 'publisher_did', 'timestamp', 'outcome', 'signature']) { expect(required).toContain(f); } }); it('entry_id is UUID format', () => { - expect(schema.definitions.AuditEntry.properties.entry_id.format).toBe('uuid'); + expect(schema.$defs.AuditEntry.properties.entry_id.format).toBe('uuid'); }); it('event_type covers 5 major categories', () => { - const types = schema.definitions.AuditEntry.properties.event_type.enum as string[]; + const types = schema.$defs.AuditEntry.properties.event_type.enum as string[]; expect(types.some(t => t.startsWith('gate.'))).toBe(true); expect(types.some(t => t.startsWith('session.'))).toBe(true); expect(types.some(t => t.startsWith('webhook.'))).toBe(true); @@ -231,26 +231,26 @@ describe('A4 — audit-log.json: delivery audit log schema and SPECIFICATION §1 }); it('event_type includes gate.proof.accepted and gate.proof.rejected', () => { - const types = schema.definitions.AuditEntry.properties.event_type.enum as string[]; + const types = schema.$defs.AuditEntry.properties.event_type.enum as string[]; expect(types).toContain('gate.proof.accepted'); expect(types).toContain('gate.proof.rejected'); }); it('event_type includes PoI validation events', () => { - const types = schema.definitions.AuditEntry.properties.event_type.enum as string[]; + const types = schema.$defs.AuditEntry.properties.event_type.enum as string[]; expect(types).toContain('poi.validated'); expect(types).toContain('poi.rejected'); }); it('actor_did and publisher_did have DID pattern validation', () => { - const actorPattern = schema.definitions.AuditEntry.properties.actor_did.pattern; - const publisherPattern = schema.definitions.AuditEntry.properties.publisher_did.pattern; + const actorPattern = schema.$defs.AuditEntry.properties.actor_did.pattern; + const publisherPattern = schema.$defs.AuditEntry.properties.publisher_did.pattern; expect(actorPattern).toContain('did:'); expect(publisherPattern).toContain('did:'); }); it('outcome is constrained enum', () => { - const outcomes = schema.definitions.AuditEntry.properties.outcome.enum as string[]; + const outcomes = schema.$defs.AuditEntry.properties.outcome.enum as string[]; expect(outcomes).toContain('success'); expect(outcomes).toContain('failure'); }); @@ -265,7 +265,7 @@ describe('A4 — audit-log.json: delivery audit log schema and SPECIFICATION §1 expect(example).toHaveProperty(f); } const entry = example.entries[0]; - for (const f of schema.definitions.AuditEntry.required) { + for (const f of schema.$defs.AuditEntry.required) { expect(entry).toHaveProperty(f); } }); diff --git a/packages/@eep-dev/gates/src/g-b1-b10.test.ts b/packages/@eep-dev/gates/src/g-b1-b10.test.ts index 06134b9..8450e50 100644 --- a/packages/@eep-dev/gates/src/g-b1-b10.test.ts +++ b/packages/@eep-dev/gates/src/g-b1-b10.test.ts @@ -190,7 +190,7 @@ describe('B4 — data.withdrawal.json: REST endpoint schema for GDPR erasure', ( it('WithdrawalRequest definition has all required fields', () => { const schema = loadSchema('data.withdrawal.json') as any; - const required: string[] = schema.definitions.WithdrawalRequest.required; + const required: string[] = schema.$defs.WithdrawalRequest.required; expect(required).toContain('claim_id'); expect(required).toContain('agent_did'); expect(required).toContain('reason'); @@ -201,7 +201,7 @@ describe('B4 — data.withdrawal.json: REST endpoint schema for GDPR erasure', ( it('WithdrawalRequest reason enum includes GDPR and CCPA bases', () => { const schema = loadSchema('data.withdrawal.json') as any; - const reasons: string[] = schema.definitions.WithdrawalRequest.properties.reason.enum; + const reasons: string[] = schema.$defs.WithdrawalRequest.properties.reason.enum; expect(reasons).toContain('gdpr_erasure'); expect(reasons).toContain('ccpa_deletion'); expect(reasons).toContain('revoke_consent'); @@ -210,7 +210,7 @@ describe('B4 — data.withdrawal.json: REST endpoint schema for GDPR erasure', ( it('WithdrawalAcknowledgement response covers 202 Accepted scenario', () => { const schema = loadSchema('data.withdrawal.json') as any; - const ack = schema.definitions.WithdrawalAcknowledgement; + const ack = schema.$defs.WithdrawalAcknowledgement; expect(ack).toBeDefined(); const required: string[] = ack.required; expect(required).toContain('withdrawal_id'); @@ -221,7 +221,7 @@ describe('B4 — data.withdrawal.json: REST endpoint schema for GDPR erasure', ( it('WithdrawalAcknowledgement status enum includes all lifecycle states', () => { const schema = loadSchema('data.withdrawal.json') as any; - const statuses: string[] = schema.definitions.WithdrawalAcknowledgement.properties.status.enum; + const statuses: string[] = schema.$defs.WithdrawalAcknowledgement.properties.status.enum; expect(statuses).toContain('pending'); expect(statuses).toContain('processing'); expect(statuses).toContain('completed'); @@ -230,7 +230,7 @@ describe('B4 — data.withdrawal.json: REST endpoint schema for GDPR erasure', ( it('data.withdrawal.json describes 24-hour publisher commitment (Whitepaper §7.3)', () => { const schema = loadSchema('data.withdrawal.json') as any; - const desc: string = schema.definitions.WithdrawalAcknowledgement.properties.expected_completion_at.description; + const desc: string = schema.$defs.WithdrawalAcknowledgement.properties.expected_completion_at.description; expect(desc).toContain('24 hours'); expect(desc.toLowerCase()).toContain('whitepaper'); }); @@ -279,7 +279,7 @@ describe('B6 — eep.dev Registry API: registry.search-result.json schema', () = it('RegistryEntry has trust_score field (0.0–1.0) as per Whitepaper §4.2', () => { const schema = loadSchema('registry.search-result.json') as any; - const entry = schema.definitions.RegistryEntry; + const entry = schema.$defs.RegistryEntry; expect(entry).toBeDefined(); expect(entry.properties.trust_score).toBeDefined(); expect(entry.properties.trust_score.minimum).toBe(0.0); @@ -288,7 +288,7 @@ describe('B6 — eep.dev Registry API: registry.search-result.json schema', () = it('RegistryEntry.conformance_tier only allows Core/Standard/Full/unverified', () => { const schema = loadSchema('registry.search-result.json') as any; - const tiers: string[] = schema.definitions.RegistryEntry.properties.conformance_tier.enum; + const tiers: string[] = schema.$defs.RegistryEntry.properties.conformance_tier.enum; expect(tiers).toContain('Core'); expect(tiers).toContain('Standard'); expect(tiers).toContain('Full'); @@ -298,7 +298,7 @@ describe('B6 — eep.dev Registry API: registry.search-result.json schema', () = it('RegistryEntry supports filtering by gate_types and layers', () => { const schema = loadSchema('registry.search-result.json') as any; - const entry = schema.definitions.RegistryEntry; + const entry = schema.$defs.RegistryEntry; expect(entry.properties.gate_types).toBeDefined(); expect(entry.properties.layers).toBeDefined(); expect(entry.properties.categories).toBeDefined(); @@ -307,7 +307,7 @@ describe('B6 — eep.dev Registry API: registry.search-result.json schema', () = it('RegistryEntry supports federation (registry_source + resolved_from)', () => { const schema = loadSchema('registry.search-result.json') as any; expect(schema.properties.resolved_from).toBeDefined(); - const entry = schema.definitions.RegistryEntry; + const entry = schema.$defs.RegistryEntry; expect(entry.properties.registry_source).toBeDefined(); }); }); @@ -447,7 +447,7 @@ describe('Cross-cutting: schema count and consistency', () => { const newSchemas = ['data.withdrawal.json', 'registry.search-result.json']; for (const schemaName of newSchemas) { const schema = loadSchema(schemaName) as any; - expect(schema.$schema).toBe('http://json-schema.org/draft-07/schema#'); + expect(schema.$schema).toBe('https://json-schema.org/draft/2020-12/schema'); expect(schema.$id).toContain('https://eep.dev/schemas/v0.1/'); } }); diff --git a/packages/@eep-dev/gates/src/g13-g22.test.ts b/packages/@eep-dev/gates/src/g13-g22.test.ts index 2e43955..5fa8921 100644 --- a/packages/@eep-dev/gates/src/g13-g22.test.ts +++ b/packages/@eep-dev/gates/src/g13-g22.test.ts @@ -573,14 +573,14 @@ describe('Proof validator: new types in batch validation', () => { it('proof type pattern includes data_request and agreement in gate.proof.json', () => { const schema = loadSchema('gate.proof.json') as any; - const pattern = schema.definitions.proof.properties.type.pattern; + const pattern = schema.$defs.proof.properties.type.pattern; expect(pattern).toContain('data_request'); expect(pattern).toContain('agreement'); }); it('gate.config.json type pattern includes data_request and agreement', () => { const schema = loadSchema('gate.config.json') as any; - const pattern = schema.definitions.requirement.properties.type.pattern; + const pattern = schema.$defs.requirement.properties.type.pattern; expect(pattern).toContain('data_request'); expect(pattern).toContain('agreement'); }); diff --git a/packages/@eep-dev/gates/src/g37-g39.test.ts b/packages/@eep-dev/gates/src/g37-g39.test.ts index 7131ac2..b6f060c 100644 --- a/packages/@eep-dev/gates/src/g37-g39.test.ts +++ b/packages/@eep-dev/gates/src/g37-g39.test.ts @@ -166,7 +166,7 @@ describe('G39 — EEPConformanceCredential JSON Schema', () => { }); it('has correct $schema and $id', () => { - expect(conformanceCredentialSchema.$schema).toBe('http://json-schema.org/draft-07/schema#'); + expect(conformanceCredentialSchema.$schema).toBe('https://json-schema.org/draft/2020-12/schema'); expect(conformanceCredentialSchema.$id).toMatch(/conformance\.credential\.json/); }); diff --git a/schemas/v0.1/agent.wallet.json b/schemas/v0.1/agent.wallet.json index b1a15bd..c21a6aa 100644 --- a/schemas/v0.1/agent.wallet.json +++ b/schemas/v0.1/agent.wallet.json @@ -1,223 +1,223 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/agent.wallet.json", - "title": "EEP Agent Wallet Binding Declaration", - "description": "Schema for the Agent Wallet Binding Declaration — a signed document declaring how an agent's operational DID is bound to its cryptographic key store. Three binding models are defined per Whitepaper §8: operator-derived (BIP-32 HD), hardware-isolated (TEE/HSM), and OS-keychain (Secure Enclave / Android Keystore / Windows CNG). This document is stored in the agent's local secure configuration and can be presented to publishers requiring it.", - "type": "object", - "required": [ - "agent_did", - "binding_model", - "key_type", - "created_at", - "rotation_policy" - ], - "additionalProperties": false, - "properties": { - "agent_did": { - "type": "string", - "description": "The operational DID derived from this wallet. This is the identity the agent uses in all EEP interactions.", - "pattern": "^did:[a-z0-9]+:.+$", - "examples": [ - "did:web:agent.acme.corp:assistant" - ] + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/agent.wallet.json", + "title": "EEP Agent Wallet Binding Declaration", + "description": "Schema for the Agent Wallet Binding Declaration \u2014 a signed document declaring how an agent's operational DID is bound to its cryptographic key store. Three binding models are defined per Whitepaper \u00a78: operator-derived (BIP-32 HD), hardware-isolated (TEE/HSM), and OS-keychain (Secure Enclave / Android Keystore / Windows CNG). This document is stored in the agent's local secure configuration and can be presented to publishers requiring it.", + "type": "object", + "required": [ + "agent_did", + "binding_model", + "key_type", + "created_at", + "rotation_policy" + ], + "additionalProperties": false, + "properties": { + "agent_did": { + "type": "string", + "description": "The operational DID derived from this wallet. This is the identity the agent uses in all EEP interactions.", + "pattern": "^did:[a-z0-9]+:.+$", + "examples": [ + "did:web:agent.acme.corp:assistant" + ] + }, + "binding_model": { + "type": "string", + "description": "The key binding model. 'operator_derived' = BIP-32 HD derivation from operator master seed. 'hardware_isolated' = TEE/HSM-bound key, never extractable. 'os_keychain' = OS Secure Enclave / Keystore / CNG.", + "enum": [ + "operator_derived", + "hardware_isolated", + "os_keychain" + ] + }, + "key_type": { + "type": "string", + "description": "The cryptographic key type used for this wallet's DID private key.", + "enum": [ + "Ed25519", + "secp256k1", + "P-256", + "ML-DSA-44", + "ML-DSA-65", + "ML-DSA-87" + ] + }, + "created_at": { + "type": "string", + "description": "ISO 8601 UTC timestamp when this wallet binding was created.", + "format": "date-time" + }, + "rotation_policy": { + "type": "object", + "description": "Key rotation policy. EEP recommends 90-day proactive rotation.", + "required": [ + "max_age_days" + ], + "additionalProperties": false, + "properties": { + "max_age_days": { + "type": "integer", + "description": "Maximum key age in days before rotation is required. Recommended: 90.", + "minimum": 1, + "maximum": 365, + "examples": [ + 90 + ] }, - "binding_model": { - "type": "string", - "description": "The key binding model. 'operator_derived' = BIP-32 HD derivation from operator master seed. 'hardware_isolated' = TEE/HSM-bound key, never extractable. 'os_keychain' = OS Secure Enclave / Keystore / CNG.", - "enum": [ - "operator_derived", - "hardware_isolated", - "os_keychain" - ] + "auto_rotate": { + "type": "boolean", + "description": "If true, the agent automatically rotates the key when max_age_days is reached without human confirmation.", + "default": false + }, + "next_rotation_at": { + "type": "string", + "description": "ISO 8601 UTC timestamp of the next scheduled rotation (informational).", + "format": "date-time" + } + } + }, + "delegation_scope": { + "type": "object", + "description": "If this is a delegated session key, this block describes the scope granted by the master DID. Absent for master keys.", + "required": [ + "master_did", + "permitted_gate_types", + "max_payment_amount_usd", + "expires_at" + ], + "additionalProperties": false, + "properties": { + "master_did": { + "type": "string", + "description": "The master DID that signed the delegation credential.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "delegation_credential_id": { + "type": "string", + "description": "W3C VC ID of the Delegation Proof credential issued by the master DID." }, - "key_type": { + "permitted_gate_types": { + "type": "array", + "description": "Gate types this session key is permitted to satisfy.", + "items": { "type": "string", - "description": "The cryptographic key type used for this wallet's DID private key.", "enum": [ - "Ed25519", - "secp256k1", - "P-256", - "ML-DSA-44", - "ML-DSA-65", - "ML-DSA-87" + "payment", + "credential", + "identity", + "agreement", + "data_request", + "proof_of_intent", + "trust" ] + }, + "minItems": 1 }, - "created_at": { - "type": "string", - "description": "ISO 8601 UTC timestamp when this wallet binding was created.", - "format": "date-time" - }, - "rotation_policy": { - "type": "object", - "description": "Key rotation policy. EEP recommends 90-day proactive rotation.", - "required": [ - "max_age_days" - ], - "additionalProperties": false, - "properties": { - "max_age_days": { - "type": "integer", - "description": "Maximum key age in days before rotation is required. Recommended: 90.", - "minimum": 1, - "maximum": 365, - "examples": [ - 90 - ] - }, - "auto_rotate": { - "type": "boolean", - "description": "If true, the agent automatically rotates the key when max_age_days is reached without human confirmation.", - "default": false - }, - "next_rotation_at": { - "type": "string", - "description": "ISO 8601 UTC timestamp of the next scheduled rotation (informational).", - "format": "date-time" - } - } - }, - "delegation_scope": { - "type": "object", - "description": "If this is a delegated session key, this block describes the scope granted by the master DID. Absent for master keys.", - "required": [ - "master_did", - "permitted_gate_types", - "max_payment_amount_usd", - "expires_at" - ], - "additionalProperties": false, - "properties": { - "master_did": { - "type": "string", - "description": "The master DID that signed the delegation credential.", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "delegation_credential_id": { - "type": "string", - "description": "W3C VC ID of the Delegation Proof credential issued by the master DID." - }, - "permitted_gate_types": { - "type": "array", - "description": "Gate types this session key is permitted to satisfy.", - "items": { - "type": "string", - "enum": [ - "payment", - "credential", - "identity", - "agreement", - "data_request", - "proof_of_intent", - "trust" - ] - }, - "minItems": 1 - }, - "permitted_endpoints": { - "type": "array", - "description": "Optional allowlist of endpoint URL patterns this key may interact with.", - "items": { - "type": "string" - }, - "examples": [ - [ - "https://api.example.com/*", - "https://data.org/v1/*" - ] - ] - }, - "max_payment_amount_usd": { - "type": "number", - "description": "Maximum payment amount in USD-equivalent that this session key may authorize per transaction.", - "minimum": 0 - }, - "expires_at": { - "type": "string", - "description": "ISO 8601 UTC expiry time of this delegation scope. Session keys should have short validity (e.g., 8h).", - "format": "date-time" - } - } + "permitted_endpoints": { + "type": "array", + "description": "Optional allowlist of endpoint URL patterns this key may interact with.", + "items": { + "type": "string" + }, + "examples": [ + [ + "https://api.example.com/*", + "https://data.org/v1/*" + ] + ] }, - "operator_derived_config": { - "type": "object", - "description": "Present only when binding_model = 'operator_derived'. BIP-32 derivation configuration.", - "required": [ - "derivation_path" - ], - "additionalProperties": false, - "properties": { - "derivation_path": { - "type": "string", - "description": "BIP-32 HD derivation path used to derive this agent's key from the operator master seed.", - "pattern": "^m(/[0-9]+'?)+$", - "examples": [ - "m/44'/60'/0'/0/0", - "m/44'/60'/1'/0/0" - ] - }, - "master_did": { - "type": "string", - "description": "The operator's master DID from which this agent key is derived.", - "pattern": "^did:[a-z0-9]+:.+$" - } - } + "max_payment_amount_usd": { + "type": "number", + "description": "Maximum payment amount in USD-equivalent that this session key may authorize per transaction.", + "minimum": 0 }, - "hardware_config": { - "type": "object", - "description": "Present only when binding_model = 'hardware_isolated'. TEE/HSM configuration.", - "additionalProperties": false, - "properties": { - "hardware_type": { - "type": "string", - "description": "The hardware security technology used.", - "enum": [ - "tpm_2.0", - "aws_nitro_enclaves", - "azure_confidential_computing", - "gcp_confidential_vm", - "hsm_pkcs11", - "sgx", - "trustzone" - ] - }, - "attestation_endpoint": { - "type": "string", - "description": "URL where remote attestation reports can be fetched to verify TEE integrity.", - "format": "uri" - } - } + "expires_at": { + "type": "string", + "description": "ISO 8601 UTC expiry time of this delegation scope. Session keys should have short validity (e.g., 8h).", + "format": "date-time" + } + } + }, + "operator_derived_config": { + "type": "object", + "description": "Present only when binding_model = 'operator_derived'. BIP-32 derivation configuration.", + "required": [ + "derivation_path" + ], + "additionalProperties": false, + "properties": { + "derivation_path": { + "type": "string", + "description": "BIP-32 HD derivation path used to derive this agent's key from the operator master seed.", + "pattern": "^m(/[0-9]+'?)+$", + "examples": [ + "m/44'/60'/0'/0/0", + "m/44'/60'/1'/0/0" + ] }, - "os_keychain_config": { - "type": "object", - "description": "Present only when binding_model = 'os_keychain'. OS keychain configuration.", - "additionalProperties": false, - "properties": { - "platform": { - "type": "string", - "description": "The OS keychain technology.", - "enum": [ - "apple_secure_enclave", - "android_keystore", - "windows_cng", - "linux_tpm" - ] - }, - "biometric_required": { - "type": "boolean", - "description": "If true, biometric authentication is required to access this key.", - "default": false - } - } + "master_did": { + "type": "string", + "description": "The operator's master DID from which this agent key is derived.", + "pattern": "^did:[a-z0-9]+:.+$" + } + } + }, + "hardware_config": { + "type": "object", + "description": "Present only when binding_model = 'hardware_isolated'. TEE/HSM configuration.", + "additionalProperties": false, + "properties": { + "hardware_type": { + "type": "string", + "description": "The hardware security technology used.", + "enum": [ + "tpm_2.0", + "aws_nitro_enclaves", + "azure_confidential_computing", + "gcp_confidential_vm", + "hsm_pkcs11", + "sgx", + "trustzone" + ] }, - "operator_did": { - "type": "string", - "description": "DID of the human or organization that operates and controls this agent.", - "pattern": "^did:[a-z0-9]+:.+$" + "attestation_endpoint": { + "type": "string", + "description": "URL where remote attestation reports can be fetched to verify TEE integrity.", + "format": "uri" + } + } + }, + "os_keychain_config": { + "type": "object", + "description": "Present only when binding_model = 'os_keychain'. OS keychain configuration.", + "additionalProperties": false, + "properties": { + "platform": { + "type": "string", + "description": "The OS keychain technology.", + "enum": [ + "apple_secure_enclave", + "android_keystore", + "windows_cng", + "linux_tpm" + ] }, - "pqc_ready": { - "type": "boolean", - "description": "Indicates whether this wallet is configured for hybrid post-quantum signing (EdDSA + ML-DSA).", - "default": false + "biometric_required": { + "type": "boolean", + "description": "If true, biometric authentication is required to access this key.", + "default": false } + } + }, + "operator_did": { + "type": "string", + "description": "DID of the human or organization that operates and controls this agent.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "pqc_ready": { + "type": "boolean", + "description": "Indicates whether this wallet is configured for hybrid post-quantum signing (EdDSA + ML-DSA).", + "default": false } -} \ No newline at end of file + } +} diff --git a/schemas/v0.1/audit-log.json b/schemas/v0.1/audit-log.json index 19e83f6..9a72e92 100644 --- a/schemas/v0.1/audit-log.json +++ b/schemas/v0.1/audit-log.json @@ -1,221 +1,221 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/audit-log.json", - "title": "EEP Delivery Audit Log Response", - "description": "Schema for responses from GET /eep/audit-log. Returns a paginated list of signed delivery records covering all agent-publisher interactions: gate proofs, session events, commerce state transitions, and webhook deliveries. Satisfies EU AI Act Art. 12 (logging), DORA Art. 8 (ICT records), and GDPR Art. 5 Data Accountability. Per Whitepaper §10.2 and §14.3 (mandated auditability). (A4).", - "type": "object", - "required": [ - "entries", - "total", - "page", - "per_page" - ], - "additionalProperties": false, - "properties": { - "entries": { - "type": "array", - "description": "Ordered list of audit log entries (newest first by default, reversible via sort=asc).", - "items": { - "$ref": "#/definitions/AuditEntry" - } + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/audit-log.json", + "title": "EEP Delivery Audit Log Response", + "description": "Schema for responses from GET /eep/audit-log. Returns a paginated list of signed delivery records covering all agent-publisher interactions: gate proofs, session events, commerce state transitions, and webhook deliveries. Satisfies EU AI Act Art. 12 (logging), DORA Art. 8 (ICT records), and GDPR Art. 5 Data Accountability. Per Whitepaper \u00a710.2 and \u00a714.3 (mandated auditability). (A4).", + "type": "object", + "required": [ + "entries", + "total", + "page", + "per_page" + ], + "additionalProperties": false, + "properties": { + "entries": { + "type": "array", + "description": "Ordered list of audit log entries (newest first by default, reversible via sort=asc).", + "items": { + "$ref": "#/$defs/AuditEntry" + } + }, + "total": { + "type": "integer", + "description": "Total number of audit entries matching the query.", + "minimum": 0 + }, + "page": { + "type": "integer", + "description": "Current page number (1-indexed).", + "minimum": 1 + }, + "per_page": { + "type": "integer", + "description": "Entries returned per page.", + "minimum": 1, + "maximum": 1000 + }, + "next_cursor": { + "type": "string", + "description": "Opaque cursor for fetching the next page. Absent when no further pages exist." + }, + "publisher_did": { + "type": "string", + "description": "DID of the publisher whose audit log is returned.", + "pattern": "^did:" + } + }, + "$defs": { + "AuditEntry": { + "type": "object", + "required": [ + "entry_id", + "event_type", + "actor_did", + "publisher_did", + "timestamp", + "outcome", + "signature" + ], + "additionalProperties": false, + "properties": { + "entry_id": { + "type": "string", + "description": "Unique, immutable identifier for this audit entry (UUID v4).", + "format": "uuid" }, - "total": { - "type": "integer", - "description": "Total number of audit entries matching the query.", - "minimum": 0 + "event_type": { + "type": "string", + "description": "The type of audited event. Uses the EEP event type namespace (com.example.*) or audit-specific prefixes.", + "enum": [ + "gate.proof.submitted", + "gate.proof.accepted", + "gate.proof.rejected", + "gate.payment.verified", + "gate.payment.rejected", + "session.created", + "session.renewed", + "session.revoked", + "session.expired", + "webhook.delivery.attempted", + "webhook.delivery.succeeded", + "webhook.delivery.failed", + "webhook.delivery.abandoned", + "commerce.offer", + "commerce.counter", + "commerce.accepted", + "commerce.invoice", + "commerce.paid", + "commerce.cancelled", + "data.withdrawal.requested", + "data.withdrawal.acknowledged", + "data.withdrawal.completed", + "poi.validated", + "poi.rejected", + "rate_limit.triggered", + "did.revocation.checked" + ] }, - "page": { - "type": "integer", - "description": "Current page number (1-indexed).", - "minimum": 1 + "actor_did": { + "type": "string", + "description": "DID of the agent or entity that initiated this event.", + "pattern": "^did:" }, - "per_page": { - "type": "integer", - "description": "Entries returned per page.", - "minimum": 1, - "maximum": 1000 + "publisher_did": { + "type": "string", + "description": "DID of the EEP publisher recording this event.", + "pattern": "^did:" }, - "next_cursor": { - "type": "string", - "description": "Opaque cursor for fetching the next page. Absent when no further pages exist." + "timestamp": { + "type": "string", + "format": "date-time", + "description": "ISO8601 UTC timestamp of when the event occurred." }, - "publisher_did": { - "type": "string", - "description": "DID of the publisher whose audit log is returned.", - "pattern": "^did:" - } - }, - "definitions": { - "AuditEntry": { - "type": "object", - "required": [ - "entry_id", - "event_type", - "actor_did", - "publisher_did", - "timestamp", - "outcome", - "signature" - ], - "additionalProperties": false, - "properties": { - "entry_id": { - "type": "string", - "description": "Unique, immutable identifier for this audit entry (UUID v4).", - "format": "uuid" - }, - "event_type": { - "type": "string", - "description": "The type of audited event. Uses the EEP event type namespace (com.example.*) or audit-specific prefixes.", - "enum": [ - "gate.proof.submitted", - "gate.proof.accepted", - "gate.proof.rejected", - "gate.payment.verified", - "gate.payment.rejected", - "session.created", - "session.renewed", - "session.revoked", - "session.expired", - "webhook.delivery.attempted", - "webhook.delivery.succeeded", - "webhook.delivery.failed", - "webhook.delivery.abandoned", - "commerce.offer", - "commerce.counter", - "commerce.accepted", - "commerce.invoice", - "commerce.paid", - "commerce.cancelled", - "data.withdrawal.requested", - "data.withdrawal.acknowledged", - "data.withdrawal.completed", - "poi.validated", - "poi.rejected", - "rate_limit.triggered", - "did.revocation.checked" - ] - }, - "actor_did": { - "type": "string", - "description": "DID of the agent or entity that initiated this event.", - "pattern": "^did:" - }, - "publisher_did": { - "type": "string", - "description": "DID of the EEP publisher recording this event.", - "pattern": "^did:" - }, - "timestamp": { - "type": "string", - "format": "date-time", - "description": "ISO8601 UTC timestamp of when the event occurred." - }, - "outcome": { - "type": "string", - "description": "Result of the audited action.", - "enum": [ - "success", - "failure", - "partial", - "pending" - ] - }, - "resource": { - "type": "string", - "description": "The resource tier or identifier the event relates to (e.g., 'premium', '/api/data/v1')." - }, - "gate_type": { - "type": "string", - "description": "For gate events: the type of gate requirement (credential, payment, agreement, data_request, identity, combined).", - "enum": [ - "credential", - "payment", - "agreement", - "data_request", - "identity", - "allowlist", - "reciprocal", - "combined" - ] - }, - "failure_reason": { - "type": "string", - "description": "Short machine-readable reason code for failures. Not surfaced to requesting agents (logged internally only per EEP §10.8).", - "examples": [ - "nonce_already_consumed", - "timestamp_outside_window", - "signature_invalid", - "did_revoked", - "insufficient_confirmations", - "double_spend" - ] - }, - "session_token_id": { - "type": "string", - "description": "If the event is tied to a session, the opaque session token identifier (not the full token)." - }, - "commerce_id": { - "type": "string", - "description": "If the event is part of a commerce negotiation, the negotiation identifier." - }, - "delivery_attempt": { - "type": "integer", - "description": "For webhook delivery events: the attempt number (1 = first attempt).", - "minimum": 1 - }, - "http_status": { - "type": "integer", - "description": "For webhook delivery events: the HTTP status code received from the subscriber endpoint.", - "examples": [ - 200, - 404, - 500, - 503 - ] - }, - "nonce": { - "type": "string", - "description": "The nonce used in the gate proof (for gate events). Stored to enforce single-use." - }, - "signature": { - "type": "string", - "description": "EdDSA (or hybrid ML-DSA) signature over (entry_id + event_type + actor_did + publisher_did + timestamp + outcome), signed by the publisher's DID key. Allows agents and auditors to verify the integrity of audit log entries. The audit log cannot be tampered with without invalidating these per-entry signatures." - }, - "metadata": { - "type": "object", - "description": "Event-specific additional metadata (e.g., transaction hash for payment events, subscription_id for webhook events, tier for session events). Not schema-validated further to allow future extensibility.", - "additionalProperties": true - } - } + "outcome": { + "type": "string", + "description": "Result of the audited action.", + "enum": [ + "success", + "failure", + "partial", + "pending" + ] + }, + "resource": { + "type": "string", + "description": "The resource tier or identifier the event relates to (e.g., 'premium', '/api/data/v1')." + }, + "gate_type": { + "type": "string", + "description": "For gate events: the type of gate requirement (credential, payment, agreement, data_request, identity, combined).", + "enum": [ + "credential", + "payment", + "agreement", + "data_request", + "identity", + "allowlist", + "reciprocal", + "combined" + ] + }, + "failure_reason": { + "type": "string", + "description": "Short machine-readable reason code for failures. Not surfaced to requesting agents (logged internally only per EEP \u00a710.8).", + "examples": [ + "nonce_already_consumed", + "timestamp_outside_window", + "signature_invalid", + "did_revoked", + "insufficient_confirmations", + "double_spend" + ] + }, + "session_token_id": { + "type": "string", + "description": "If the event is tied to a session, the opaque session token identifier (not the full token)." + }, + "commerce_id": { + "type": "string", + "description": "If the event is part of a commerce negotiation, the negotiation identifier." + }, + "delivery_attempt": { + "type": "integer", + "description": "For webhook delivery events: the attempt number (1 = first attempt).", + "minimum": 1 + }, + "http_status": { + "type": "integer", + "description": "For webhook delivery events: the HTTP status code received from the subscriber endpoint.", + "examples": [ + 200, + 404, + 500, + 503 + ] + }, + "nonce": { + "type": "string", + "description": "The nonce used in the gate proof (for gate events). Stored to enforce single-use." + }, + "signature": { + "type": "string", + "description": "EdDSA (or hybrid ML-DSA) signature over (entry_id + event_type + actor_did + publisher_did + timestamp + outcome), signed by the publisher's DID key. Allows agents and auditors to verify the integrity of audit log entries. The audit log cannot be tampered with without invalidating these per-entry signatures." + }, + "metadata": { + "type": "object", + "description": "Event-specific additional metadata (e.g., transaction hash for payment events, subscription_id for webhook events, tier for session events). Not schema-validated further to allow future extensibility.", + "additionalProperties": true } - }, - "examples": [ + } + } + }, + "examples": [ + { + "entries": [ { - "entries": [ - { - "entry_id": "d290f1ee-6c54-4b01-90e6-d701748f0851", - "event_type": "gate.proof.accepted", - "actor_did": "did:web:agent.example.com", - "publisher_did": "did:web:api.example.com", - "timestamp": "2026-03-05T10:00:00Z", - "outcome": "success", - "resource": "premium", - "gate_type": "payment", - "session_token_id": "sess_01J9Z", - "nonce": "nonce_abc123", - "signature": "z3K2nRgW9F...", - "metadata": { - "tx_hash": "0xdeadbeef...", - "chain": "base", - "amount_usd": "0.001" - } - } - ], - "total": 142, - "page": 1, - "per_page": 20, - "publisher_did": "did:web:api.example.com" + "entry_id": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "event_type": "gate.proof.accepted", + "actor_did": "did:web:agent.example.com", + "publisher_did": "did:web:api.example.com", + "timestamp": "2026-03-05T10:00:00Z", + "outcome": "success", + "resource": "premium", + "gate_type": "payment", + "session_token_id": "sess_01J9Z", + "nonce": "nonce_abc123", + "signature": "z3K2nRgW9F...", + "metadata": { + "tx_hash": "0xdeadbeef...", + "chain": "base", + "amount_usd": "0.001" + } } - ] -} \ No newline at end of file + ], + "total": 142, + "page": 1, + "per_page": 20, + "publisher_did": "did:web:api.example.com" + } + ] +} diff --git a/schemas/v0.1/commerce.negotiation.json b/schemas/v0.1/commerce.negotiation.json index 113c836..ef92519 100644 --- a/schemas/v0.1/commerce.negotiation.json +++ b/schemas/v0.1/commerce.negotiation.json @@ -1,448 +1,448 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/commerce.negotiation.json", - "title": "EEP Commerce Negotiation", - "description": "Schema for commerce messages exchanged over EEP Network Pulse (WebSocket). Commerce messages enable bidirectional price negotiation between agents and entities. Pricing models are extensible; the protocol defines standard models but implementers can add custom ones via x- prefix.", - "type": "object", - "required": [ - "negotiation_id", - "service" - ], - "additionalProperties": false, - "properties": { - "negotiation_id": { - "type": "string", - "description": "Unique identifier for this negotiation session. Generated by the party that sends the initial offer.", - "pattern": "^neg_[a-zA-Z0-9]{8,32}$", - "examples": [ - "neg_01abc2def3" - ] + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/commerce.negotiation.json", + "title": "EEP Commerce Negotiation", + "description": "Schema for commerce messages exchanged over EEP Network Pulse (WebSocket). Commerce messages enable bidirectional price negotiation between agents and entities. Pricing models are extensible; the protocol defines standard models but implementers can add custom ones via x- prefix.", + "type": "object", + "required": [ + "negotiation_id", + "service" + ], + "additionalProperties": false, + "properties": { + "negotiation_id": { + "type": "string", + "description": "Unique identifier for this negotiation session. Generated by the party that sends the initial offer.", + "pattern": "^neg_[a-zA-Z0-9]{8,32}$", + "examples": [ + "neg_01abc2def3" + ] + }, + "service": { + "type": "string", + "description": "Identifier or name of the service being negotiated. Can be a service listing ID or a freeform description.", + "minLength": 1, + "maxLength": 256, + "examples": [ + "svc_consultation_30", + "data_feed.premium", + "profile.full_access" + ] + }, + "pricing": { + "$ref": "#/$defs/pricing", + "description": "The pricing terms being proposed in this message." + }, + "terms": { + "$ref": "#/$defs/terms", + "description": "Additional terms and conditions for this negotiation." + }, + "reason": { + "type": "string", + "description": "Optional reason (used with reject or counter actions).", + "maxLength": 1024, + "examples": [ + "Price too high for this volume", + "Service unavailable at requested time" + ] + }, + "invoice": { + "$ref": "#/$defs/invoice", + "description": "Invoice details (used with the 'invoice' action after service delivery)." + }, + "receipt": { + "$ref": "#/$defs/receipt", + "description": "Payment receipt (used with the 'receipt' action to confirm payment)." + }, + "metadata": { + "type": "object", + "description": "Optional party-defined metadata.", + "additionalProperties": true, + "maxProperties": 20 + }, + "pricing_mode": { + "type": "string", + "description": "Pricing discovery mode. fixed: static price list; negotiable: bilateral counter-offer; auction: open RFP auction. (\u00a77.3, G19).", + "enum": [ + "fixed", + "negotiable", + "auction" + ], + "default": "fixed" + }, + "auction": { + "type": "object", + "description": "Auction configuration \u2014 only present when pricing_mode is 'auction'.", + "required": [ + "mechanism", + "close_time", + "currency" + ], + "additionalProperties": false, + "properties": { + "mechanism": { + "type": "string", + "description": "Auction mechanism type. first_price: highest bidder wins at their price; vickrey: highest bidder wins at second price; reverse: lowest offer wins.", + "enum": [ + "first_price", + "vickrey", + "reverse" + ] }, - "service": { - "type": "string", - "description": "Identifier or name of the service being negotiated. Can be a service listing ID or a freeform description.", - "minLength": 1, - "maxLength": 256, - "examples": [ - "svc_consultation_30", - "data_feed.premium", - "profile.full_access" - ] + "close_time": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 datetime when bidding closes." }, - "pricing": { - "$ref": "#/definitions/pricing", - "description": "The pricing terms being proposed in this message." + "reserve_price": { + "type": "number", + "description": "Minimum acceptable price (for first_price/vickrey) or maximum acceptable cost (for reverse). Optional.", + "minimum": 0 }, - "terms": { - "$ref": "#/definitions/terms", - "description": "Additional terms and conditions for this negotiation." + "currency": { + "type": "string", + "description": "ISO 4217 currency code.", + "pattern": "^[a-z]{3}$" }, - "reason": { - "type": "string", - "description": "Optional reason (used with reject or counter actions).", - "maxLength": 1024, - "examples": [ - "Price too high for this volume", - "Service unavailable at requested time" - ] + "rfp_id": { + "type": "string", + "description": "Unique RFP identifier. Carried in commerce.rfp.* CloudEvents.", + "pattern": "^rfp_[a-zA-Z0-9]{8,32}$" + } + } + }, + "allocation_receipt": { + "type": "object", + "description": "W3C VC-structured Allocation Receipt issued to auction winner. Only present in commerce.rfp.closed messages. (\u00a77.3 AllocationReceipt, G19).", + "required": [ + "@context", + "type", + "issuer", + "issuanceDate", + "credentialSubject" + ], + "additionalProperties": true, + "properties": { + "@context": { + "type": "array", + "items": { + "type": "string" + } }, - "invoice": { - "$ref": "#/definitions/invoice", - "description": "Invoice details (used with the 'invoice' action after service delivery)." + "type": { + "type": "array", + "items": { + "type": "string" + } }, - "receipt": { - "$ref": "#/definitions/receipt", - "description": "Payment receipt (used with the 'receipt' action to confirm payment)." + "issuer": { + "type": "string", + "pattern": "^did:[a-z0-9]+:.+$" }, - "metadata": { - "type": "object", - "description": "Optional party-defined metadata.", - "additionalProperties": true, - "maxProperties": 20 + "issuanceDate": { + "type": "string", + "format": "date-time" }, - "pricing_mode": { - "type": "string", - "description": "Pricing discovery mode. fixed: static price list; negotiable: bilateral counter-offer; auction: open RFP auction. (§7.3, G19).", - "enum": [ - "fixed", - "negotiable", - "auction" - ], - "default": "fixed" - }, - "auction": { - "type": "object", - "description": "Auction configuration — only present when pricing_mode is 'auction'.", - "required": [ - "mechanism", - "close_time", - "currency" - ], - "additionalProperties": false, - "properties": { - "mechanism": { - "type": "string", - "description": "Auction mechanism type. first_price: highest bidder wins at their price; vickrey: highest bidder wins at second price; reverse: lowest offer wins.", - "enum": [ - "first_price", - "vickrey", - "reverse" - ] - }, - "close_time": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 datetime when bidding closes." - }, - "reserve_price": { - "type": "number", - "description": "Minimum acceptable price (for first_price/vickrey) or maximum acceptable cost (for reverse). Optional.", - "minimum": 0 - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code.", - "pattern": "^[a-z]{3}$" - }, - "rfp_id": { - "type": "string", - "description": "Unique RFP identifier. Carried in commerce.rfp.* CloudEvents.", - "pattern": "^rfp_[a-zA-Z0-9]{8,32}$" - } + "credentialSubject": { + "type": "object", + "required": [ + "id", + "allocation_id", + "winning_bid", + "currency", + "valid_from" + ], + "properties": { + "id": { + "type": "string" + }, + "allocation_id": { + "type": "string" + }, + "winning_bid": { + "type": "number", + "minimum": 0 + }, + "currency": { + "type": "string", + "pattern": "^[a-z]{3}$" + }, + "service_id": { + "type": "string" + }, + "valid_from": { + "type": "string", + "format": "date-time" + }, + "valid_until": { + "type": "string", + "format": "date-time" } + } + } + } + } + }, + "$defs": { + "pricing": { + "type": "object", + "required": [ + "model", + "currency" + ], + "additionalProperties": false, + "properties": { + "model": { + "type": "string", + "description": "Pricing model. Standard models: fixed, per_request, per_event, subscription, metered, tiered_volume. Custom models via x- prefix.", + "pattern": "^(fixed|per_request|per_event|subscription|metered|tiered_volume|x-[a-z][a-z0-9_-]*)$" + }, + "amount": { + "type": "number", + "description": "Price amount. Must be non-negative. Zero means free.", + "minimum": 0 + }, + "currency": { + "type": "string", + "description": "ISO 4217 currency code (lowercase).", + "pattern": "^[a-z]{3}$", + "examples": [ + "usd", + "eur", + "gbp" + ] + }, + "period": { + "type": "string", + "description": "Billing period (for subscription model).", + "enum": [ + "hour", + "day", + "week", + "month", + "year" + ] + }, + "unit": { + "type": "string", + "description": "The billable unit (for metered model).", + "examples": [ + "token", + "request", + "event", + "byte", + "minute" + ] + }, + "rate": { + "type": "number", + "description": "Rate per unit (for metered model).", + "minimum": 0 }, - "allocation_receipt": { + "tiers": { + "type": "array", + "description": "Volume tiers (for tiered_volume model).", + "items": { "type": "object", - "description": "W3C VC-structured Allocation Receipt issued to auction winner. Only present in commerce.rfp.closed messages. (§7.3 AllocationReceipt, G19).", "required": [ - "@context", - "type", - "issuer", - "issuanceDate", - "credentialSubject" + "up_to", + "rate" ], - "additionalProperties": true, "properties": { - "@context": { - "type": "array", - "items": { - "type": "string" - } - }, - "type": { - "type": "array", - "items": { - "type": "string" - } - }, - "issuer": { - "type": "string", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "issuanceDate": { - "type": "string", - "format": "date-time" - }, - "credentialSubject": { - "type": "object", - "required": [ - "id", - "allocation_id", - "winning_bid", - "currency", - "valid_from" - ], - "properties": { - "id": { - "type": "string" - }, - "allocation_id": { - "type": "string" - }, - "winning_bid": { - "type": "number", - "minimum": 0 - }, - "currency": { - "type": "string", - "pattern": "^[a-z]{3}$" - }, - "service_id": { - "type": "string" - }, - "valid_from": { - "type": "string", - "format": "date-time" - }, - "valid_until": { - "type": "string", - "format": "date-time" - } - } - } + "up_to": { + "type": [ + "integer", + "string" + ], + "description": "Upper bound of this tier. Use 'infinity' for the final tier.", + "examples": [ + 1000, + 10000, + "infinity" + ] + }, + "rate": { + "type": "number", + "description": "Price per unit in this tier.", + "minimum": 0 + } } + } + }, + "minimum_charge": { + "type": "number", + "description": "Optional minimum charge regardless of usage.", + "minimum": 0 + }, + "maximum_charge": { + "type": "number", + "description": "Optional maximum charge (price cap).", + "minimum": 0 } + } }, - "definitions": { - "pricing": { - "type": "object", - "required": [ - "model", - "currency" - ], - "additionalProperties": false, - "properties": { - "model": { - "type": "string", - "description": "Pricing model. Standard models: fixed, per_request, per_event, subscription, metered, tiered_volume. Custom models via x- prefix.", - "pattern": "^(fixed|per_request|per_event|subscription|metered|tiered_volume|x-[a-z][a-z0-9_-]*)$" - }, - "amount": { - "type": "number", - "description": "Price amount. Must be non-negative. Zero means free.", - "minimum": 0 - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code (lowercase).", - "pattern": "^[a-z]{3}$", - "examples": [ - "usd", - "eur", - "gbp" - ] - }, - "period": { - "type": "string", - "description": "Billing period (for subscription model).", - "enum": [ - "hour", - "day", - "week", - "month", - "year" - ] - }, - "unit": { - "type": "string", - "description": "The billable unit (for metered model).", - "examples": [ - "token", - "request", - "event", - "byte", - "minute" - ] - }, - "rate": { - "type": "number", - "description": "Rate per unit (for metered model).", - "minimum": 0 - }, - "tiers": { - "type": "array", - "description": "Volume tiers (for tiered_volume model).", - "items": { - "type": "object", - "required": [ - "up_to", - "rate" - ], - "properties": { - "up_to": { - "type": [ - "integer", - "string" - ], - "description": "Upper bound of this tier. Use 'infinity' for the final tier.", - "examples": [ - 1000, - 10000, - "infinity" - ] - }, - "rate": { - "type": "number", - "description": "Price per unit in this tier.", - "minimum": 0 - } - } - } - }, - "minimum_charge": { - "type": "number", - "description": "Optional minimum charge regardless of usage.", - "minimum": 0 - }, - "maximum_charge": { - "type": "number", - "description": "Optional maximum charge (price cap).", - "minimum": 0 - } - } + "terms": { + "type": "object", + "additionalProperties": false, + "properties": { + "delivery": { + "type": "string", + "description": "How the service will be delivered.", + "enum": [ + "realtime", + "async", + "scheduled", + "sse", + "webhook", + "download" + ] }, - "terms": { - "type": "object", - "additionalProperties": false, - "properties": { - "delivery": { - "type": "string", - "description": "How the service will be delivered.", - "enum": [ - "realtime", - "async", - "scheduled", - "sse", - "webhook", - "download" - ] - }, - "expires_in": { - "type": "integer", - "description": "Seconds until this offer expires. After expiry, the negotiation transitions to 'expired' state.", - "minimum": 60, - "maximum": 2592000 - }, - "conditions": { - "type": "array", - "description": "Free-text conditions attached to this offer.", - "items": { - "type": "string", - "maxLength": 256 - }, - "maxItems": 10 - }, - "cancellation_policy": { - "type": "string", - "description": "Cancellation terms.", - "enum": [ - "none", - "full_refund", - "partial_refund", - "no_refund" - ], - "default": "none" - }, - "sla": { - "type": "object", - "description": "Optional service level agreement.", - "properties": { - "uptime_percent": { - "type": "number", - "minimum": 0, - "maximum": 100 - }, - "response_time_ms": { - "type": "integer", - "minimum": 0 - }, - "support_hours": { - "type": "string" - } - } - } + "expires_in": { + "type": "integer", + "description": "Seconds until this offer expires. After expiry, the negotiation transitions to 'expired' state.", + "minimum": 60, + "maximum": 2592000 + }, + "conditions": { + "type": "array", + "description": "Free-text conditions attached to this offer.", + "items": { + "type": "string", + "maxLength": 256 + }, + "maxItems": 10 + }, + "cancellation_policy": { + "type": "string", + "description": "Cancellation terms.", + "enum": [ + "none", + "full_refund", + "partial_refund", + "no_refund" + ], + "default": "none" + }, + "sla": { + "type": "object", + "description": "Optional service level agreement.", + "properties": { + "uptime_percent": { + "type": "number", + "minimum": 0, + "maximum": 100 + }, + "response_time_ms": { + "type": "integer", + "minimum": 0 + }, + "support_hours": { + "type": "string" } + } + } + } + }, + "invoice": { + "type": "object", + "required": [ + "invoice_id", + "amount", + "currency" + ], + "additionalProperties": false, + "properties": { + "invoice_id": { + "type": "string", + "description": "Unique invoice identifier.", + "examples": [ + "inv_01abc" + ] }, - "invoice": { + "amount": { + "type": "number", + "description": "Total amount due.", + "minimum": 0 + }, + "currency": { + "type": "string", + "pattern": "^[a-z]{3}$" + }, + "line_items": { + "type": "array", + "description": "Breakdown of charges.", + "items": { "type": "object", - "required": [ - "invoice_id", - "amount", - "currency" - ], - "additionalProperties": false, "properties": { - "invoice_id": { - "type": "string", - "description": "Unique invoice identifier.", - "examples": [ - "inv_01abc" - ] - }, - "amount": { - "type": "number", - "description": "Total amount due.", - "minimum": 0 - }, - "currency": { - "type": "string", - "pattern": "^[a-z]{3}$" - }, - "line_items": { - "type": "array", - "description": "Breakdown of charges.", - "items": { - "type": "object", - "properties": { - "description": { - "type": "string" - }, - "quantity": { - "type": "number" - }, - "unit_price": { - "type": "number" - }, - "total": { - "type": "number" - } - } - } - }, - "payment_methods": { - "type": "array", - "description": "URLs or identifiers for payment methods.", - "items": { - "type": "string" - } - }, - "due_by": { - "type": "string", - "description": "Payment deadline (ISO 8601).", - "format": "date-time" - } + "description": { + "type": "string" + }, + "quantity": { + "type": "number" + }, + "unit_price": { + "type": "number" + }, + "total": { + "type": "number" + } } + } }, - "receipt": { - "type": "object", - "required": [ - "receipt_id", - "payment_proof" - ], - "additionalProperties": false, - "properties": { - "receipt_id": { - "type": "string", - "description": "Unique receipt identifier." - }, - "invoice_id": { - "type": "string", - "description": "The invoice this payment is for." - }, - "payment_proof": { - "type": "object", - "description": "Proof of payment (provider-specific, opaque to protocol).", - "required": [ - "type", - "token" - ], - "properties": { - "type": { - "type": "string" - }, - "token": { - "type": "string" - }, - "provider": { - "type": "string" - } - } - }, - "paid_at": { - "type": "string", - "format": "date-time" - } + "payment_methods": { + "type": "array", + "description": "URLs or identifiers for payment methods.", + "items": { + "type": "string" + } + }, + "due_by": { + "type": "string", + "description": "Payment deadline (ISO 8601).", + "format": "date-time" + } + } + }, + "receipt": { + "type": "object", + "required": [ + "receipt_id", + "payment_proof" + ], + "additionalProperties": false, + "properties": { + "receipt_id": { + "type": "string", + "description": "Unique receipt identifier." + }, + "invoice_id": { + "type": "string", + "description": "The invoice this payment is for." + }, + "payment_proof": { + "type": "object", + "description": "Proof of payment (provider-specific, opaque to protocol).", + "required": [ + "type", + "token" + ], + "properties": { + "type": { + "type": "string" + }, + "token": { + "type": "string" + }, + "provider": { + "type": "string" } + } + }, + "paid_at": { + "type": "string", + "format": "date-time" } + } } -} \ No newline at end of file + } +} diff --git a/schemas/v0.1/conformance.credential.json b/schemas/v0.1/conformance.credential.json index 6deaba2..bc58a16 100644 --- a/schemas/v0.1/conformance.credential.json +++ b/schemas/v0.1/conformance.credential.json @@ -1,292 +1,292 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/conformance.credential.json", - "title": "EEP Conformance Credential", - "description": "W3C Verifiable Credential 2.0-compatible schema for the EEP Conformance Credential issued by eep.dev to publishers that pass the EEP conformance test suite. See SPECIFICATION.md §10.2 and Whitepaper §10.2. Publishers include this credential in their /.well-known/eep.json manifest under the `conformance_credential` field. Agents verify the credential on first contact without querying any registry.", - "type": "object", - "required": [ - "@context", - "type", - "issuer", - "validFrom", - "validUntil", - "credentialSubject", - "proof" - ], - "additionalProperties": true, - "properties": { - "@context": { - "type": "array", - "description": "JSON-LD context. Must include W3C VC 2.0 and EEP contexts.", - "items": { - "type": "string" - }, - "contains": { - "const": "https://www.w3.org/ns/credentials/v2" - }, - "examples": [ - [ - "https://www.w3.org/ns/credentials/v2", - "https://eep.dev/contexts/v0.1" - ] - ] + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/conformance.credential.json", + "title": "EEP Conformance Credential", + "description": "W3C Verifiable Credential 2.0-compatible schema for the EEP Conformance Credential issued by eep.dev to publishers that pass the EEP conformance test suite. See SPECIFICATION.md \u00a710.2 and Whitepaper \u00a710.2. Publishers include this credential in their /.well-known/eep.json manifest under the `conformance_credential` field. Agents verify the credential on first contact without querying any registry.", + "type": "object", + "required": [ + "@context", + "type", + "issuer", + "validFrom", + "validUntil", + "credentialSubject", + "proof" + ], + "additionalProperties": true, + "properties": { + "@context": { + "type": "array", + "description": "JSON-LD context. Must include W3C VC 2.0 and EEP contexts.", + "items": { + "type": "string" + }, + "contains": { + "const": "https://www.w3.org/ns/credentials/v2" + }, + "examples": [ + [ + "https://www.w3.org/ns/credentials/v2", + "https://eep.dev/contexts/v0.1" + ] + ] + }, + "type": { + "type": "array", + "description": "VC type. Must include 'VerifiableCredential' and one of the EEP conformance tier types.", + "items": { + "type": "string" + }, + "allOf": [ + { + "contains": { + "const": "VerifiableCredential" + } }, - "type": { - "type": "array", - "description": "VC type. Must include 'VerifiableCredential' and one of the EEP conformance tier types.", - "items": { - "type": "string" - }, - "allOf": [ - { - "contains": { - "const": "VerifiableCredential" - } - }, - { - "contains": { - "enum": [ - "EEPConformanceCredential_Core", - "EEPConformanceCredential_Standard", - "EEPConformanceCredential_Full" - ] - } - } - ], - "examples": [ - [ - "VerifiableCredential", - "EEPConformanceCredential_Full" - ] + { + "contains": { + "enum": [ + "EEPConformanceCredential_Core", + "EEPConformanceCredential_Standard", + "EEPConformanceCredential_Full" ] + } + } + ], + "examples": [ + [ + "VerifiableCredential", + "EEPConformanceCredential_Full" + ] + ] + }, + "id": { + "type": "string", + "description": "Unique identifier for this credential instance.", + "format": "uri", + "examples": [ + "https://eep.dev/credentials/conformance/01HN3QK7GX" + ] + }, + "issuer": { + "description": "The DID of the issuer. Must be eep.dev's authoritative DID for the credential to be trusted.", + "oneOf": [ + { + "type": "string", + "pattern": "^did:[a-z0-9]+:.+$" }, + { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "name": { + "type": "string" + } + } + } + ], + "examples": [ + "did:web:eep.dev" + ] + }, + "validFrom": { + "type": "string", + "description": "ISO 8601 UTC timestamp when this credential becomes valid (date of conformance test passing).", + "format": "date-time", + "examples": [ + "2026-03-05T12:00:00Z" + ] + }, + "validUntil": { + "type": "string", + "description": "ISO 8601 UTC timestamp when this credential expires. Per Whitepaper \u00a710.2, conformance credentials expire annually and must be renewed. Agents MUST reject expired conformance credentials.", + "format": "date-time", + "examples": [ + "2027-03-05T12:00:00Z" + ] + }, + "credentialSubject": { + "type": "object", + "required": [ + "id", + "conformanceTier", + "testedAt", + "passedChecks" + ], + "additionalProperties": true, + "description": "The publisher that passed the conformance test suite.", + "properties": { "id": { - "type": "string", - "description": "Unique identifier for this credential instance.", - "format": "uri", - "examples": [ - "https://eep.dev/credentials/conformance/01HN3QK7GX" - ] + "type": "string", + "description": "The DID of the publisher that passed conformance testing.", + "pattern": "^did:[a-z0-9]+:.+$", + "examples": [ + "did:web:api.publisher.example" + ] }, - "issuer": { - "description": "The DID of the issuer. Must be eep.dev's authoritative DID for the credential to be trusted.", - "oneOf": [ - { - "type": "string", - "pattern": "^did:[a-z0-9]+:.+$" - }, - { - "type": "object", - "required": [ - "id" - ], - "properties": { - "id": { - "type": "string", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "name": { - "type": "string" - } - } - } - ], - "examples": [ - "did:web:eep.dev" - ] + "conformanceTier": { + "type": "string", + "description": "The EEP conformance tier the publisher achieved. Per Whitepaper \u00a710.2 Table 2: Core (Layer 1 + L2 SSE), Standard (Core + Webhooks + credential/payment gates + version negotiation), Full (Standard + L3 WebSockets + commerce + agreement + data_request + session persistence + W3C DPV).", + "enum": [ + "Core", + "Standard", + "Full" + ], + "examples": [ + "Full" + ] }, - "validFrom": { - "type": "string", - "description": "ISO 8601 UTC timestamp when this credential becomes valid (date of conformance test passing).", - "format": "date-time", - "examples": [ - "2026-03-05T12:00:00Z" - ] + "eepVersion": { + "type": "string", + "description": "The EEP specification version against which conformance was tested.", + "examples": [ + "0.1" + ] }, - "validUntil": { - "type": "string", - "description": "ISO 8601 UTC timestamp when this credential expires. Per Whitepaper §10.2, conformance credentials expire annually and must be renewed. Agents MUST reject expired conformance credentials.", - "format": "date-time", - "examples": [ - "2027-03-05T12:00:00Z" - ] + "testedAt": { + "type": "string", + "description": "ISO 8601 UTC timestamp when the conformance test suite was run.", + "format": "date-time", + "examples": [ + "2026-03-05T10:30:00Z" + ] }, - "credentialSubject": { - "type": "object", - "required": [ - "id", - "conformanceTier", - "testedAt", - "passedChecks" - ], - "additionalProperties": true, - "description": "The publisher that passed the conformance test suite.", - "properties": { - "id": { - "type": "string", - "description": "The DID of the publisher that passed conformance testing.", - "pattern": "^did:[a-z0-9]+:.+$", - "examples": [ - "did:web:api.publisher.example" - ] - }, - "conformanceTier": { - "type": "string", - "description": "The EEP conformance tier the publisher achieved. Per Whitepaper §10.2 Table 2: Core (Layer 1 + L2 SSE), Standard (Core + Webhooks + credential/payment gates + version negotiation), Full (Standard + L3 WebSockets + commerce + agreement + data_request + session persistence + W3C DPV).", - "enum": [ - "Core", - "Standard", - "Full" - ], - "examples": [ - "Full" - ] - }, - "eepVersion": { - "type": "string", - "description": "The EEP specification version against which conformance was tested.", - "examples": [ - "0.1" - ] - }, - "testedAt": { - "type": "string", - "description": "ISO 8601 UTC timestamp when the conformance test suite was run.", - "format": "date-time", - "examples": [ - "2026-03-05T10:30:00Z" - ] - }, - "passedChecks": { - "type": "integer", - "description": "Number of conformance checks passed. Informational.", - "minimum": 1, - "examples": [ - 47 - ] - }, - "totalChecks": { - "type": "integer", - "description": "Total number of conformance checks run. Informational.", - "minimum": 1, - "examples": [ - 47 - ] - }, - "manifestUrl": { - "type": "string", - "description": "URL of the publisher's /.well-known/eep.json manifest that was tested.", - "format": "uri", - "examples": [ - "https://api.publisher.example/.well-known/eep.json" - ] - }, - "sectorExtensions": { - "type": "array", - "description": "Sector-specific conformance extensions (e.g., EEP-FinServ-1.0) that were also tested and passed. See Whitepaper §11.4 and GOVERNANCE.md.", - "items": { - "type": "string", - "pattern": "^EEP-[A-Za-z]+(-[A-Za-z]+)?-\\d+\\.\\d+$" - }, - "examples": [ - [ - "EEP-FinServ-1.0" - ] - ] - } - } + "passedChecks": { + "type": "integer", + "description": "Number of conformance checks passed. Informational.", + "minimum": 1, + "examples": [ + 47 + ] }, - "proof": { - "type": "object", - "required": [ - "type", - "created", - "verificationMethod", - "proofPurpose", - "proofValue" - ], - "description": "Cryptographic proof over the credential, signed by eep.dev's DID private key. Agents MUST verify this proof before trusting the credential.", - "properties": { - "type": { - "type": "string", - "description": "Proof type. EEP uses Ed25519Signature2020 or DataIntegrityProof.", - "enum": [ - "Ed25519Signature2020", - "DataIntegrityProof" - ], - "examples": [ - "Ed25519Signature2020" - ] - }, - "created": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 UTC timestamp when the proof was created.", - "examples": [ - "2026-03-05T12:00:00Z" - ] - }, - "verificationMethod": { - "type": "string", - "description": "DID URL of the key used to sign this credential. Must resolve to a key in eep.dev's DID Document.", - "examples": [ - "did:web:eep.dev#key-1" - ] - }, - "proofPurpose": { - "type": "string", - "description": "Purpose of the proof. Must be 'assertionMethod' for conformance credentials.", - "const": "assertionMethod" - }, - "proofValue": { - "type": "string", - "description": "Base64url-encoded cryptographic proof value.", - "minLength": 16, - "examples": [ - "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz" - ] - }, - "cryptosuite": { - "type": "string", - "description": "Cryptosuite identifier when type is DataIntegrityProof.", - "examples": [ - "eddsa-rdfc-2022", - "ecdsa-rdfc-2019" - ] - } - } + "totalChecks": { + "type": "integer", + "description": "Total number of conformance checks run. Informational.", + "minimum": 1, + "examples": [ + 47 + ] + }, + "manifestUrl": { + "type": "string", + "description": "URL of the publisher's /.well-known/eep.json manifest that was tested.", + "format": "uri", + "examples": [ + "https://api.publisher.example/.well-known/eep.json" + ] + }, + "sectorExtensions": { + "type": "array", + "description": "Sector-specific conformance extensions (e.g., EEP-FinServ-1.0) that were also tested and passed. See Whitepaper \u00a711.4 and GOVERNANCE.md.", + "items": { + "type": "string", + "pattern": "^EEP-[A-Za-z]+(-[A-Za-z]+)?-\\d+\\.\\d+$" + }, + "examples": [ + [ + "EEP-FinServ-1.0" + ] + ] } + } }, - "examples": [ - { - "@context": [ - "https://www.w3.org/ns/credentials/v2", - "https://eep.dev/contexts/v0.1" - ], - "type": [ - "VerifiableCredential", - "EEPConformanceCredential_Full" - ], - "id": "https://eep.dev/credentials/conformance/01HN3QK7GX", - "issuer": "did:web:eep.dev", - "validFrom": "2026-03-05T12:00:00Z", - "validUntil": "2027-03-05T12:00:00Z", - "credentialSubject": { - "id": "did:web:api.publisher.example", - "conformanceTier": "Full", - "eepVersion": "0.1", - "testedAt": "2026-03-05T10:30:00Z", - "passedChecks": 47, - "totalChecks": 47, - "manifestUrl": "https://api.publisher.example/.well-known/eep.json" - }, - "proof": { - "type": "Ed25519Signature2020", - "created": "2026-03-05T12:00:00Z", - "verificationMethod": "did:web:eep.dev#key-1", - "proofPurpose": "assertionMethod", - "proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz" - } + "proof": { + "type": "object", + "required": [ + "type", + "created", + "verificationMethod", + "proofPurpose", + "proofValue" + ], + "description": "Cryptographic proof over the credential, signed by eep.dev's DID private key. Agents MUST verify this proof before trusting the credential.", + "properties": { + "type": { + "type": "string", + "description": "Proof type. EEP uses Ed25519Signature2020 or DataIntegrityProof.", + "enum": [ + "Ed25519Signature2020", + "DataIntegrityProof" + ], + "examples": [ + "Ed25519Signature2020" + ] + }, + "created": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 UTC timestamp when the proof was created.", + "examples": [ + "2026-03-05T12:00:00Z" + ] + }, + "verificationMethod": { + "type": "string", + "description": "DID URL of the key used to sign this credential. Must resolve to a key in eep.dev's DID Document.", + "examples": [ + "did:web:eep.dev#key-1" + ] + }, + "proofPurpose": { + "type": "string", + "description": "Purpose of the proof. Must be 'assertionMethod' for conformance credentials.", + "const": "assertionMethod" + }, + "proofValue": { + "type": "string", + "description": "Base64url-encoded cryptographic proof value.", + "minLength": 16, + "examples": [ + "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz" + ] + }, + "cryptosuite": { + "type": "string", + "description": "Cryptosuite identifier when type is DataIntegrityProof.", + "examples": [ + "eddsa-rdfc-2022", + "ecdsa-rdfc-2019" + ] } - ] -} \ No newline at end of file + } + } + }, + "examples": [ + { + "@context": [ + "https://www.w3.org/ns/credentials/v2", + "https://eep.dev/contexts/v0.1" + ], + "type": [ + "VerifiableCredential", + "EEPConformanceCredential_Full" + ], + "id": "https://eep.dev/credentials/conformance/01HN3QK7GX", + "issuer": "did:web:eep.dev", + "validFrom": "2026-03-05T12:00:00Z", + "validUntil": "2027-03-05T12:00:00Z", + "credentialSubject": { + "id": "did:web:api.publisher.example", + "conformanceTier": "Full", + "eepVersion": "0.1", + "testedAt": "2026-03-05T10:30:00Z", + "passedChecks": 47, + "totalChecks": 47, + "manifestUrl": "https://api.publisher.example/.well-known/eep.json" + }, + "proof": { + "type": "Ed25519Signature2020", + "created": "2026-03-05T12:00:00Z", + "verificationMethod": "did:web:eep.dev#key-1", + "proofPurpose": "assertionMethod", + "proofValue": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz" + } + } + ] +} diff --git a/schemas/v0.1/data.withdrawal.json b/schemas/v0.1/data.withdrawal.json index b9dac2b..383180a 100644 --- a/schemas/v0.1/data.withdrawal.json +++ b/schemas/v0.1/data.withdrawal.json @@ -1,157 +1,157 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/data.withdrawal.json", - "title": "EEP Data Withdrawal", - "description": "Schema for the EEP data withdrawal mechanism defined in Whitepaper §7.3 (Right of Withdrawal). An agent's operator may instruct it to withdraw a previously provided data claim via WebSocket `data.withdrawal` message OR via the dedicated REST endpoint `DELETE /data/claims/:claim_id`. This schema covers both the REST request body and the publisher's 202 Accepted response. Publishers MUST acknowledge within 24 hours and purge the withdrawn claim data while keeping the session token valid.", - "definitions": { - "WithdrawalRequest": { - "$id": "#WithdrawalRequest", - "title": "Data Withdrawal Request", - "description": "Body sent by the agent to DELETE /data/claims/:claim_id or as a WebSocket data.withdrawal message payload.", - "type": "object", - "required": [ - "claim_id", - "agent_did", - "reason", - "issued_at", - "nonce", - "signature" - ], - "additionalProperties": false, - "properties": { - "claim_id": { - "type": "string", - "description": "Identifier of the specific data claim to withdraw. Must match a previously provided claim from a data_request gate exchange.", - "examples": [ - "claim_org_type_20260305_abc123", - "urn:eep:claim:01HN3QK7GX" - ] - }, - "agent_did": { - "type": "string", - "description": "DID of the requesting agent. Must match the DID that originally provided the claim.", - "pattern": "^did:[a-z0-9]+:.+$", - "examples": [ - "did:web:agent.acme.corp" - ] - }, - "publisher_did": { - "type": "string", - "description": "DID of the publisher holding the claim data. Used for targeted withdrawal in multi-publisher deployments.", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "reason": { - "type": "string", - "description": "Machine-readable reason code for the withdrawal. Logged by publisher for GDPR Art. 17 accountability.", - "enum": [ - "gdpr_erasure", - "ccpa_deletion", - "purpose_fulfilled", - "revoke_consent", - "operator_instruction", - "other" - ] - }, - "reason_detail": { - "type": "string", - "description": "Optional human-readable explanation for 'other' reason codes.", - "maxLength": 512 - }, - "issued_at": { - "type": "string", - "description": "ISO 8601 UTC timestamp when this withdrawal request was created. Must be within 60 seconds per EEP replay prevention.", - "format": "date-time", - "examples": [ - "2026-03-05T14:00:00Z" - ] - }, - "nonce": { - "type": "string", - "description": "Single-use nonce. Publisher must verify this nonce was issued for this agent and mark it consumed to prevent replay.", - "minLength": 16, - "maxLength": 128 - }, - "signature": { - "type": "string", - "description": "EdDSA signature (base64url) by agent_did's private key over canonical JSON of all fields except 'signature'. Establishes non-repudiable withdrawal request.", - "minLength": 16 - } - } + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/data.withdrawal.json", + "title": "EEP Data Withdrawal", + "description": "Schema for the EEP data withdrawal mechanism defined in Whitepaper \u00a77.3 (Right of Withdrawal). An agent's operator may instruct it to withdraw a previously provided data claim via WebSocket `data.withdrawal` message OR via the dedicated REST endpoint `DELETE /data/claims/:claim_id`. This schema covers both the REST request body and the publisher's 202 Accepted response. Publishers MUST acknowledge within 24 hours and purge the withdrawn claim data while keeping the session token valid.", + "$defs": { + "WithdrawalRequest": { + "$id": "#WithdrawalRequest", + "title": "Data Withdrawal Request", + "description": "Body sent by the agent to DELETE /data/claims/:claim_id or as a WebSocket data.withdrawal message payload.", + "type": "object", + "required": [ + "claim_id", + "agent_did", + "reason", + "issued_at", + "nonce", + "signature" + ], + "additionalProperties": false, + "properties": { + "claim_id": { + "type": "string", + "description": "Identifier of the specific data claim to withdraw. Must match a previously provided claim from a data_request gate exchange.", + "examples": [ + "claim_org_type_20260305_abc123", + "urn:eep:claim:01HN3QK7GX" + ] }, - "WithdrawalAcknowledgement": { - "$id": "#WithdrawalAcknowledgement", - "title": "Data Withdrawal Acknowledgement (202 Accepted)", - "description": "HTTP 202 Accepted response body when deletion is asynchronous. Publisher commits to completing withdrawal within expected_completion_at.", - "type": "object", - "required": [ - "withdrawal_id", - "claim_id", - "status", - "acknowledged_at", - "expected_completion_at" - ], - "additionalProperties": false, - "properties": { - "withdrawal_id": { - "type": "string", - "description": "Unique identifier for this withdrawal request. Agent can poll GET /data/claims/:claim_id/status using this ID.", - "examples": [ - "withdrawal_01HN3QK7GX", - "urn:eep:withdrawal:2026-03-05T14:00:00Z:abc123" - ] - }, - "claim_id": { - "type": "string", - "description": "The claim_id being withdrawn (echoed for confirmation)." - }, - "status": { - "type": "string", - "description": "Current status of the withdrawal.", - "enum": [ - "pending", - "processing", - "completed", - "failed" - ] - }, - "acknowledged_at": { - "type": "string", - "description": "ISO 8601 UTC timestamp when the publisher acknowledged the withdrawal request.", - "format": "date-time" - }, - "expected_completion_at": { - "type": "string", - "description": "ISO 8601 UTC timestamp by which the publisher commits to completing deletion. Per Whitepaper §7.3: default window is 24 hours.", - "format": "date-time" - }, - "publisher_signature": { - "type": "string", - "description": "EdDSA signature by publisher_did over canonical JSON of this document. Makes the acknowledgement tamper-evident and legally binding.", - "minLength": 16 - } - } + "agent_did": { + "type": "string", + "description": "DID of the requesting agent. Must match the DID that originally provided the claim.", + "pattern": "^did:[a-z0-9]+:.+$", + "examples": [ + "did:web:agent.acme.corp" + ] + }, + "publisher_did": { + "type": "string", + "description": "DID of the publisher holding the claim data. Used for targeted withdrawal in multi-publisher deployments.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "reason": { + "type": "string", + "description": "Machine-readable reason code for the withdrawal. Logged by publisher for GDPR Art. 17 accountability.", + "enum": [ + "gdpr_erasure", + "ccpa_deletion", + "purpose_fulfilled", + "revoke_consent", + "operator_instruction", + "other" + ] + }, + "reason_detail": { + "type": "string", + "description": "Optional human-readable explanation for 'other' reason codes.", + "maxLength": 512 + }, + "issued_at": { + "type": "string", + "description": "ISO 8601 UTC timestamp when this withdrawal request was created. Must be within 60 seconds per EEP replay prevention.", + "format": "date-time", + "examples": [ + "2026-03-05T14:00:00Z" + ] + }, + "nonce": { + "type": "string", + "description": "Single-use nonce. Publisher must verify this nonce was issued for this agent and mark it consumed to prevent replay.", + "minLength": 16, + "maxLength": 128 + }, + "signature": { + "type": "string", + "description": "EdDSA signature (base64url) by agent_did's private key over canonical JSON of all fields except 'signature'. Establishes non-repudiable withdrawal request.", + "minLength": 16 } + } }, - "examples": [ - { - "$comment": "Example 1: REST withdrawal request body", - "withdrawal_request": { - "claim_id": "claim_org_type_20260305_abc123", - "agent_did": "did:web:agent.acme.corp", - "publisher_did": "did:web:data.example.org", - "reason": "gdpr_erasure", - "issued_at": "2026-03-05T14:00:00Z", - "nonce": "nOncE-1a2b3c4d5e6f7g8h", - "signature": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz" - }, - "acknowledgement_202": { - "withdrawal_id": "withdrawal_01HN3QK7GX", - "claim_id": "claim_org_type_20260305_abc123", - "status": "pending", - "acknowledged_at": "2026-03-05T14:00:01Z", - "expected_completion_at": "2026-03-06T14:00:01Z", - "publisher_signature": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz" - } + "WithdrawalAcknowledgement": { + "$id": "#WithdrawalAcknowledgement", + "title": "Data Withdrawal Acknowledgement (202 Accepted)", + "description": "HTTP 202 Accepted response body when deletion is asynchronous. Publisher commits to completing withdrawal within expected_completion_at.", + "type": "object", + "required": [ + "withdrawal_id", + "claim_id", + "status", + "acknowledged_at", + "expected_completion_at" + ], + "additionalProperties": false, + "properties": { + "withdrawal_id": { + "type": "string", + "description": "Unique identifier for this withdrawal request. Agent can poll GET /data/claims/:claim_id/status using this ID.", + "examples": [ + "withdrawal_01HN3QK7GX", + "urn:eep:withdrawal:2026-03-05T14:00:00Z:abc123" + ] + }, + "claim_id": { + "type": "string", + "description": "The claim_id being withdrawn (echoed for confirmation)." + }, + "status": { + "type": "string", + "description": "Current status of the withdrawal.", + "enum": [ + "pending", + "processing", + "completed", + "failed" + ] + }, + "acknowledged_at": { + "type": "string", + "description": "ISO 8601 UTC timestamp when the publisher acknowledged the withdrawal request.", + "format": "date-time" + }, + "expected_completion_at": { + "type": "string", + "description": "ISO 8601 UTC timestamp by which the publisher commits to completing deletion. Per Whitepaper \u00a77.3: default window is 24 hours.", + "format": "date-time" + }, + "publisher_signature": { + "type": "string", + "description": "EdDSA signature by publisher_did over canonical JSON of this document. Makes the acknowledgement tamper-evident and legally binding.", + "minLength": 16 } - ] -} \ No newline at end of file + } + } + }, + "examples": [ + { + "$comment": "Example 1: REST withdrawal request body", + "withdrawal_request": { + "claim_id": "claim_org_type_20260305_abc123", + "agent_did": "did:web:agent.acme.corp", + "publisher_did": "did:web:data.example.org", + "reason": "gdpr_erasure", + "issued_at": "2026-03-05T14:00:00Z", + "nonce": "nOncE-1a2b3c4d5e6f7g8h", + "signature": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz" + }, + "acknowledgement_202": { + "withdrawal_id": "withdrawal_01HN3QK7GX", + "claim_id": "claim_org_type_20260305_abc123", + "status": "pending", + "acknowledged_at": "2026-03-05T14:00:01Z", + "expected_completion_at": "2026-03-06T14:00:01Z", + "publisher_signature": "z58DAdFfa9SkqZMVPxAQpic7ndSayn1PzZs6ZjWp1CktyGesjuTSwRdoWhAfGFCF5bppETSTojQCrfFPP2oumHKtz" + } + } + ] +} diff --git a/schemas/v0.1/delegation.proof.json b/schemas/v0.1/delegation.proof.json index ce78735..45958ee 100644 --- a/schemas/v0.1/delegation.proof.json +++ b/schemas/v0.1/delegation.proof.json @@ -1,186 +1,186 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/delegation.proof.json", - "title": "EEP Delegation Proof Verifiable Credential", - "description": "A W3C Verifiable Credential issued by an owner DID to an agent DID, defining the permitted actions, endpoints, and spend limits for the delegation. Must be presented alongside the agent's proof for any delegated gate interaction. (§13 Agent Delegation Chains, Whitepaper).", - "type": "object", - "required": [ - "@context", - "type", - "issuer", - "issuanceDate", - "credentialSubject", - "proof" - ], - "additionalProperties": true, - "properties": { - "@context": { - "type": "array", - "description": "JSON-LD context array. Must contain W3C VC context and EEP context.", - "items": { - "type": "string" - }, - "contains": { - "const": "https://www.w3.org/2018/credentials/v1" - }, - "minItems": 1, + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/delegation.proof.json", + "title": "EEP Delegation Proof Verifiable Credential", + "description": "A W3C Verifiable Credential issued by an owner DID to an agent DID, defining the permitted actions, endpoints, and spend limits for the delegation. Must be presented alongside the agent's proof for any delegated gate interaction. (\u00a713 Agent Delegation Chains, Whitepaper).", + "type": "object", + "required": [ + "@context", + "type", + "issuer", + "issuanceDate", + "credentialSubject", + "proof" + ], + "additionalProperties": true, + "properties": { + "@context": { + "type": "array", + "description": "JSON-LD context array. Must contain W3C VC context and EEP context.", + "items": { + "type": "string" + }, + "contains": { + "const": "https://www.w3.org/2018/credentials/v1" + }, + "minItems": 1, + "examples": [ + [ + "https://www.w3.org/2018/credentials/v1", + "https://eep.dev/contexts/v0.1" + ] + ] + }, + "type": { + "type": "array", + "description": "VC type array. Must contain both VerifiableCredential and EEPDelegationProof.", + "items": { + "type": "string" + }, + "contains": { + "const": "EEPDelegationProof" + }, + "examples": [ + [ + "VerifiableCredential", + "EEPDelegationProof" + ] + ] + }, + "issuer": { + "type": "string", + "description": "DID of the entity delegating authority (the owner or parent agent).", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "issuanceDate": { + "type": "string", + "description": "ISO 8601 datetime when this delegation credential was issued.", + "format": "date-time" + }, + "expirationDate": { + "type": "string", + "description": "ISO 8601 datetime when this delegation expires. Agents presenting expired delegation credentials must be rejected.", + "format": "date-time" + }, + "credentialSubject": { + "type": "object", + "required": [ + "id", + "permitted_actions" + ], + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "description": "DID of the delegate (the agent being granted authority).", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "permitted_actions": { + "type": "array", + "description": "Explicit list of actions this agent may perform. Agents requesting actions outside this list must be rejected. Delegation credentials without explicit scope restrictions are rejected.", + "minItems": 1, + "items": { + "type": "string", "examples": [ - [ - "https://www.w3.org/2018/credentials/v1", - "https://eep.dev/contexts/v0.1" - ] + "gate:payment", + "gate:credential", + "subscribe:sse", + "commerce:offer" ] + } }, - "type": { - "type": "array", - "description": "VC type array. Must contain both VerifiableCredential and EEPDelegationProof.", - "items": { - "type": "string" - }, - "contains": { - "const": "EEPDelegationProof" - }, - "examples": [ - [ - "VerifiableCredential", - "EEPDelegationProof" - ] + "permitted_endpoints": { + "type": "array", + "description": "URL patterns the agent is permitted to call. Supports glob patterns (e.g., https://api.example.com/*).", + "items": { + "type": "string" + }, + "examples": [ + [ + "https://api.example.com/*", + "https://api.example.com/v1/data/*" ] + ] }, - "issuer": { - "type": "string", - "description": "DID of the entity delegating authority (the owner or parent agent).", - "pattern": "^did:[a-z0-9]+:.+$" + "max_payment_amount": { + "type": "number", + "description": "Maximum total payment amount (in currency_code units) the agent may authorise without additional delegation.", + "minimum": 0 }, - "issuanceDate": { - "type": "string", - "description": "ISO 8601 datetime when this delegation credential was issued.", - "format": "date-time" + "currency_code": { + "type": "string", + "description": "ISO 4217 currency code for max_payment_amount.", + "pattern": "^[A-Z]{3}$" + }, + "scope_hash": { + "type": "string", + "description": "SHA-256 hash of the canonical JSON serialization of this credentialSubject (excluding scope_hash). Used for tamper detection.", + "pattern": "^sha256:[a-f0-9]{64}$" }, - "expirationDate": { + "operator_privacy_policy_hash": { + "type": "string", + "description": "SHA-256 of the Operator Privacy Policy document the delegator binds sub-agents to (SPEC \u00a711.8). SHOULD be present when delegation may touch data_request gates.", + "pattern": "^sha256:[a-f0-9]{64}$" + }, + "allowed_dpv_purposes": { + "type": "array", + "description": "W3C DPV purpose URIs the delegate may claim under data_request (subset of operator policy).", + "items": { "type": "string", - "description": "ISO 8601 datetime when this delegation expires. Agents presenting expired delegation credentials must be rejected.", - "format": "date-time" + "pattern": "^dpv:[A-Z][a-zA-Z]+$" + }, + "minItems": 1 + }, + "max_retention_days": { + "type": "integer", + "description": "Maximum retention days the delegate may commit to on behalf of the operator.", + "minimum": 0, + "maximum": 3650 + } + } + }, + "proof": { + "type": "object", + "description": "W3C VC Linked Data Proof or JWT proof from the issuer DID key.", + "required": [ + "type", + "verificationMethod", + "proofValue" + ], + "additionalProperties": true, + "properties": { + "type": { + "type": "string", + "examples": [ + "Ed25519Signature2020", + "JsonWebSignature2020" + ] + }, + "created": { + "type": "string", + "format": "date-time" + }, + "verificationMethod": { + "type": "string", + "description": "DID key fragment URI of the verification key used to sign.", + "examples": [ + "did:web:owner.acme.ai#key-1" + ] }, - "credentialSubject": { - "type": "object", - "required": [ - "id", - "permitted_actions" - ], - "additionalProperties": false, - "properties": { - "id": { - "type": "string", - "description": "DID of the delegate (the agent being granted authority).", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "permitted_actions": { - "type": "array", - "description": "Explicit list of actions this agent may perform. Agents requesting actions outside this list must be rejected. Delegation credentials without explicit scope restrictions are rejected.", - "minItems": 1, - "items": { - "type": "string", - "examples": [ - "gate:payment", - "gate:credential", - "subscribe:sse", - "commerce:offer" - ] - } - }, - "permitted_endpoints": { - "type": "array", - "description": "URL patterns the agent is permitted to call. Supports glob patterns (e.g., https://api.example.com/*).", - "items": { - "type": "string" - }, - "examples": [ - [ - "https://api.example.com/*", - "https://api.example.com/v1/data/*" - ] - ] - }, - "max_payment_amount": { - "type": "number", - "description": "Maximum total payment amount (in currency_code units) the agent may authorise without additional delegation.", - "minimum": 0 - }, - "currency_code": { - "type": "string", - "description": "ISO 4217 currency code for max_payment_amount.", - "pattern": "^[A-Z]{3}$" - }, - "scope_hash": { - "type": "string", - "description": "SHA-256 hash of the canonical JSON serialization of this credentialSubject (excluding scope_hash). Used for tamper detection.", - "pattern": "^sha256:[a-f0-9]{64}$" - }, - "operator_privacy_policy_hash": { - "type": "string", - "description": "SHA-256 of the Operator Privacy Policy document the delegator binds sub-agents to (SPEC §11.8). SHOULD be present when delegation may touch data_request gates.", - "pattern": "^sha256:[a-f0-9]{64}$" - }, - "allowed_dpv_purposes": { - "type": "array", - "description": "W3C DPV purpose URIs the delegate may claim under data_request (subset of operator policy).", - "items": { - "type": "string", - "pattern": "^dpv:[A-Z][a-zA-Z]+$" - }, - "minItems": 1 - }, - "max_retention_days": { - "type": "integer", - "description": "Maximum retention days the delegate may commit to on behalf of the operator.", - "minimum": 0, - "maximum": 3650 - } - } + "proofPurpose": { + "type": "string", + "enum": [ + "assertionMethod", + "authentication" + ], + "default": "assertionMethod" }, - "proof": { - "type": "object", - "description": "W3C VC Linked Data Proof or JWT proof from the issuer DID key.", - "required": [ - "type", - "verificationMethod", - "proofValue" - ], - "additionalProperties": true, - "properties": { - "type": { - "type": "string", - "examples": [ - "Ed25519Signature2020", - "JsonWebSignature2020" - ] - }, - "created": { - "type": "string", - "format": "date-time" - }, - "verificationMethod": { - "type": "string", - "description": "DID key fragment URI of the verification key used to sign.", - "examples": [ - "did:web:owner.acme.ai#key-1" - ] - }, - "proofPurpose": { - "type": "string", - "enum": [ - "assertionMethod", - "authentication" - ], - "default": "assertionMethod" - }, - "proofValue": { - "type": "string", - "description": "Multibase-encoded proof value.", - "minLength": 10 - } - } + "proofValue": { + "type": "string", + "description": "Multibase-encoded proof value.", + "minLength": 10 } + } } -} \ No newline at end of file + } +} diff --git a/schemas/v0.1/delivery.payload.json b/schemas/v0.1/delivery.payload.json index e144802..6940701 100644 --- a/schemas/v0.1/delivery.payload.json +++ b/schemas/v0.1/delivery.payload.json @@ -1,94 +1,94 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/delivery.payload.json", - "title": "EEP Webhook Delivery Payload", - "description": "Schema for the full HTTP POST body delivered to a webhook subscriber. Extends event.envelope.json with delivery-specific metadata: unique delivery ID, publisher DID, HMAC-SHA256 delivery signature (sent in X-EEP-Signature header), retry state, and Standard Webhooks (standardwebhooks.com) compatibility headers. Publishers MUST include eep_subscription_id, eep_delivery_id, and eep_delivery_timestamp on every delivery. Agents MUST verify X-EEP-Signature before processing the payload. (A7, Whitepaper §5.2, security.md §2).", - "allOf": [ - { - "$ref": "./event.envelope.json" - } - ], - "required": [ - "specversion", - "id", - "source", - "type", - "time", - "datacontenttype", - "eep_subscription_id", - "eep_delivery_id", - "eep_delivery_timestamp" - ], - "properties": { - "eep_subscription_id": { - "type": "string", - "description": "REQUIRED. Identifies which active subscription triggered this delivery. Matches the `subscription_id` returned at subscription creation time.", - "minLength": 1 - }, - "eep_delivery_id": { - "type": "string", - "description": "REQUIRED. Globally unique, immutable identifier for this specific delivery attempt. Subscribers MUST use this as an idempotency key to deduplicate retried deliveries. UUID v4 format.", - "format": "uuid" - }, - "eep_delivery_timestamp": { - "type": "string", - "format": "date-time", - "description": "REQUIRED. ISO8601 UTC timestamp of when this delivery was dispatched from the publisher. Used by subscribers to detect staleness and by the audit log to record delivery timing." - }, - "eep_delivery_attempt": { - "type": "integer", - "description": "The delivery attempt number (1 = first attempt, 2 = first retry, etc.). Useful for debugging. Publishers SHOULD include this on all deliveries.", - "minimum": 1, - "default": 1 - }, - "eep_publisher_did": { - "type": "string", - "description": "DID of the publisher sending this delivery. Allows subscribers to verify the X-EEP-Signature using the publisher's DID key (for Ed25519-signed deliveries) or the shared HMAC secret. Enables zero-trust webhook verification without prior registration of the publisher.", - "pattern": "^did:" - }, - "eep_next_retry_at": { - "type": "string", - "format": "date-time", - "description": "ISO8601 UTC timestamp after which the publisher will attempt the next retry if this delivery fails. Uses exponential backoff: attempt N is retried after min(2^N * 30s, 86400s). Absent on the last attempt." - }, - "eep_max_attempts": { - "type": "integer", - "description": "Total number of delivery attempts the publisher will make before abandoning this event for this subscription (default: 5). Subscribers can use this to predict when delivery will be abandoned and trigger manual recovery.", - "minimum": 1, - "default": 5 - }, - "eep_signature_algorithm": { - "type": "string", - "description": "Algorithm used to compute the X-EEP-Signature header value. 'hmac-sha256': HMAC-SHA256 keyed against the subscription secret (subscriber-verifiable without DID lookup). 'eddsa': EdDSA signature over the raw body, signed by eep_publisher_did's key (verifiable via DID Document). Hybrid mode sends both.", - "enum": [ - "hmac-sha256", - "eddsa", - "hybrid-hmac-eddsa" - ], - "default": "hmac-sha256" - } + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/delivery.payload.json", + "title": "EEP Webhook Delivery Payload", + "description": "Schema for the full HTTP POST body delivered to a webhook subscriber. Extends event.envelope.json with delivery-specific metadata: unique delivery ID, publisher DID, HMAC-SHA256 delivery signature (sent in X-EEP-Signature header), retry state, and Standard Webhooks (standardwebhooks.com) compatibility headers. Publishers MUST include eep_subscription_id, eep_delivery_id, and eep_delivery_timestamp on every delivery. Agents MUST verify X-EEP-Signature before processing the payload. (A7, Whitepaper \u00a75.2, security.md \u00a72).", + "allOf": [ + { + "$ref": "./event.envelope.json" + } + ], + "required": [ + "specversion", + "id", + "source", + "type", + "time", + "datacontenttype", + "eep_subscription_id", + "eep_delivery_id", + "eep_delivery_timestamp" + ], + "properties": { + "eep_subscription_id": { + "type": "string", + "description": "REQUIRED. Identifies which active subscription triggered this delivery. Matches the `subscription_id` returned at subscription creation time.", + "minLength": 1 }, - "definitions": {}, - "examples": [ - { - "specversion": "1.0", - "id": "evt_01HXYZ", - "source": "did:web:api.example.com", - "type": "com.example.entity.updated", - "time": "2026-03-05T10:00:00Z", - "datacontenttype": "application/json", - "data": { - "entity_id": "alice", - "field": "bio", - "value": "Updated bio" - }, - "eep_subscription_id": "sub_01ABC", - "eep_delivery_id": "d290f1ee-6c54-4b01-90e6-d701748f0851", - "eep_delivery_timestamp": "2026-03-05T10:00:01Z", - "eep_delivery_attempt": 1, - "eep_publisher_did": "did:web:api.example.com", - "eep_max_attempts": 5, - "eep_signature_algorithm": "hmac-sha256" - } - ] -} \ No newline at end of file + "eep_delivery_id": { + "type": "string", + "description": "REQUIRED. Globally unique, immutable identifier for this specific delivery attempt. Subscribers MUST use this as an idempotency key to deduplicate retried deliveries. UUID v4 format.", + "format": "uuid" + }, + "eep_delivery_timestamp": { + "type": "string", + "format": "date-time", + "description": "REQUIRED. ISO8601 UTC timestamp of when this delivery was dispatched from the publisher. Used by subscribers to detect staleness and by the audit log to record delivery timing." + }, + "eep_delivery_attempt": { + "type": "integer", + "description": "The delivery attempt number (1 = first attempt, 2 = first retry, etc.). Useful for debugging. Publishers SHOULD include this on all deliveries.", + "minimum": 1, + "default": 1 + }, + "eep_publisher_did": { + "type": "string", + "description": "DID of the publisher sending this delivery. Allows subscribers to verify the X-EEP-Signature using the publisher's DID key (for Ed25519-signed deliveries) or the shared HMAC secret. Enables zero-trust webhook verification without prior registration of the publisher.", + "pattern": "^did:" + }, + "eep_next_retry_at": { + "type": "string", + "format": "date-time", + "description": "ISO8601 UTC timestamp after which the publisher will attempt the next retry if this delivery fails. Uses exponential backoff: attempt N is retried after min(2^N * 30s, 86400s). Absent on the last attempt." + }, + "eep_max_attempts": { + "type": "integer", + "description": "Total number of delivery attempts the publisher will make before abandoning this event for this subscription (default: 5). Subscribers can use this to predict when delivery will be abandoned and trigger manual recovery.", + "minimum": 1, + "default": 5 + }, + "eep_signature_algorithm": { + "type": "string", + "description": "Algorithm used to compute the X-EEP-Signature header value. 'hmac-sha256': HMAC-SHA256 keyed against the subscription secret (subscriber-verifiable without DID lookup). 'eddsa': EdDSA signature over the raw body, signed by eep_publisher_did's key (verifiable via DID Document). Hybrid mode sends both.", + "enum": [ + "hmac-sha256", + "eddsa", + "hybrid-hmac-eddsa" + ], + "default": "hmac-sha256" + } + }, + "$defs": {}, + "examples": [ + { + "specversion": "1.0", + "id": "evt_01HXYZ", + "source": "did:web:api.example.com", + "type": "com.example.entity.updated", + "time": "2026-03-05T10:00:00Z", + "datacontenttype": "application/json", + "data": { + "entity_id": "alice", + "field": "bio", + "value": "Updated bio" + }, + "eep_subscription_id": "sub_01ABC", + "eep_delivery_id": "d290f1ee-6c54-4b01-90e6-d701748f0851", + "eep_delivery_timestamp": "2026-03-05T10:00:01Z", + "eep_delivery_attempt": 1, + "eep_publisher_did": "did:web:api.example.com", + "eep_max_attempts": 5, + "eep_signature_algorithm": "hmac-sha256" + } + ] +} diff --git a/schemas/v0.1/eep-manifest.json b/schemas/v0.1/eep-manifest.json index 2f740df..e330316 100644 --- a/schemas/v0.1/eep-manifest.json +++ b/schemas/v0.1/eep-manifest.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://eep.dev/schemas/v0.1/eep-manifest.json", "title": "EEP Manifest", "description": "The /.well-known/eep.json manifest declaring an entity's EEP capabilities", diff --git a/schemas/v0.1/eep-pulse-message-schema.json b/schemas/v0.1/eep-pulse-message-schema.json index f7a1098..7b0e07f 100644 --- a/schemas/v0.1/eep-pulse-message-schema.json +++ b/schemas/v0.1/eep-pulse-message-schema.json @@ -1,225 +1,225 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/eep-pulse-message-schema.json", - "title": "EEP Network Pulse Message Schema", - "description": "JSON Schema for WebSocket messages in the EEP Network Pulse (Layer 3). All messages use a { v, type, action, seq?, data? } envelope.", - "oneOf": [ - { - "$ref": "#/$defs/SystemMessage" + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/eep-pulse-message-schema.json", + "title": "EEP Network Pulse Message Schema", + "description": "JSON Schema for WebSocket messages in the EEP Network Pulse (Layer 3). All messages use a { v, type, action, seq?, data? } envelope.", + "oneOf": [ + { + "$ref": "#/$defs/SystemMessage" + }, + { + "$ref": "#/$defs/EntityMessage" + }, + { + "$ref": "#/$defs/A2AMessage" + }, + { + "$ref": "#/$defs/ChatMessage" + }, + { + "$ref": "#/$defs/CommerceMessage" + } + ], + "$defs": { + "BaseEnvelope": { + "type": "object", + "required": [ + "v", + "type", + "action" + ], + "properties": { + "v": { + "type": "integer", + "const": 1, + "description": "Protocol version. Clients MUST disconnect on version mismatch." }, - { - "$ref": "#/$defs/EntityMessage" + "seq": { + "type": "integer", + "description": "Monotonic sequence number per channel. Used for gap detection and replay." }, + "data": { + "type": "object", + "description": "Action-specific payload." + } + } + }, + "SystemMessage": { + "allOf": [ { - "$ref": "#/$defs/A2AMessage" + "$ref": "#/$defs/BaseEnvelope" + } + ], + "properties": { + "type": { + "const": "system" }, + "action": { + "type": "string", + "enum": [ + "connected", + "ping", + "pong", + "subscribe", + "subscribed", + "unsubscribe", + "unsubscribed", + "replay", + "replay_complete", + "gap_detected", + "auth_expiring", + "auth_refresh", + "auth_refreshed", + "auth_expired", + "error" + ] + } + }, + "required": [ + "type", + "action" + ] + }, + "EntityMessage": { + "allOf": [ { - "$ref": "#/$defs/ChatMessage" + "$ref": "#/$defs/BaseEnvelope" + } + ], + "properties": { + "type": { + "const": "entity" + }, + "action": { + "type": "string", + "enum": [ + "update", + "publish", + "delete" + ] }, + "data": { + "type": "object", + "required": [ + "source_did" + ], + "properties": { + "source_did": { + "type": "string", + "pattern": "^did:", + "description": "DID of the entity originating this event." + } + } + } + }, + "required": [ + "type", + "action" + ] + }, + "A2AMessage": { + "allOf": [ { - "$ref": "#/$defs/CommerceMessage" + "$ref": "#/$defs/BaseEnvelope" } - ], - "$defs": { - "BaseEnvelope": { - "type": "object", - "required": [ - "v", - "type", - "action" - ], - "properties": { - "v": { - "type": "integer", - "const": 1, - "description": "Protocol version. Clients MUST disconnect on version mismatch." - }, - "seq": { - "type": "integer", - "description": "Monotonic sequence number per channel. Used for gap detection and replay." - }, - "data": { - "type": "object", - "description": "Action-specific payload." - } - } - }, - "SystemMessage": { - "allOf": [ - { - "$ref": "#/$defs/BaseEnvelope" - } - ], - "properties": { - "type": { - "const": "system" - }, - "action": { - "type": "string", - "enum": [ - "connected", - "ping", - "pong", - "subscribe", - "subscribed", - "unsubscribe", - "unsubscribed", - "replay", - "replay_complete", - "gap_detected", - "auth_expiring", - "auth_refresh", - "auth_refreshed", - "auth_expired", - "error" - ] - } - }, - "required": [ - "type", - "action" - ] + ], + "properties": { + "type": { + "const": "a2a" }, - "EntityMessage": { - "allOf": [ - { - "$ref": "#/$defs/BaseEnvelope" - } - ], - "properties": { - "type": { - "const": "entity" - }, - "action": { - "type": "string", - "enum": [ - "update", - "publish", - "delete" - ] - }, - "data": { - "type": "object", - "required": [ - "source_did" - ], - "properties": { - "source_did": { - "type": "string", - "pattern": "^did:", - "description": "DID of the entity originating this event." - } - } - } - }, - "required": [ - "type", - "action" - ] + "action": { + "type": "string", + "enum": [ + "task_request", + "task_accepted", + "task_received", + "task_progress", + "task_progress_ack", + "task_complete", + "task_complete_ack", + "task_failed", + "task_failed_ack", + "task_cancel", + "task_cancel_ack", + "task_cancelled" + ] + } + }, + "required": [ + "type", + "action" + ] + }, + "ChatMessage": { + "allOf": [ + { + "$ref": "#/$defs/BaseEnvelope" + } + ], + "properties": { + "type": { + "const": "chat" }, - "A2AMessage": { - "allOf": [ - { - "$ref": "#/$defs/BaseEnvelope" - } - ], - "properties": { - "type": { - "const": "a2a" - }, - "action": { - "type": "string", - "enum": [ - "task_request", - "task_accepted", - "task_received", - "task_progress", - "task_progress_ack", - "task_complete", - "task_complete_ack", - "task_failed", - "task_failed_ack", - "task_cancel", - "task_cancel_ack", - "task_cancelled" - ] - } - }, - "required": [ - "type", - "action" - ] + "action": { + "type": "string", + "enum": [ + "send", + "sent", + "received", + "history", + "read", + "read_ack" + ] + } + }, + "required": [ + "type", + "action" + ] + }, + "CommerceMessage": { + "allOf": [ + { + "$ref": "#/$defs/BaseEnvelope" + } + ], + "properties": { + "type": { + "const": "commerce" }, - "ChatMessage": { - "allOf": [ - { - "$ref": "#/$defs/BaseEnvelope" - } - ], - "properties": { - "type": { - "const": "chat" - }, - "action": { - "type": "string", - "enum": [ - "send", - "sent", - "received", - "history", - "read", - "read_ack" - ] - } - }, - "required": [ - "type", - "action" - ] + "action": { + "type": "string", + "description": "Commerce negotiation actions. See commerce.negotiation.json for data payload schema.", + "enum": [ + "offer", + "counter", + "accept", + "reject", + "expire", + "invoice", + "receipt", + "complete", + "dispute" + ] }, - "CommerceMessage": { - "allOf": [ - { - "$ref": "#/$defs/BaseEnvelope" - } - ], - "properties": { - "type": { - "const": "commerce" - }, - "action": { - "type": "string", - "description": "Commerce negotiation actions. See commerce.negotiation.json for data payload schema.", - "enum": [ - "offer", - "counter", - "accept", - "reject", - "expire", - "invoice", - "receipt", - "complete", - "dispute" - ] - }, - "data": { - "type": "object", - "required": [ - "negotiation_id" - ], - "properties": { - "negotiation_id": { - "type": "string", - "pattern": "^neg_[a-zA-Z0-9]{8,32}$", - "description": "Unique negotiation session identifier." - } - } - } - }, - "required": [ - "type", - "action" - ] + "data": { + "type": "object", + "required": [ + "negotiation_id" + ], + "properties": { + "negotiation_id": { + "type": "string", + "pattern": "^neg_[a-zA-Z0-9]{8,32}$", + "description": "Unique negotiation session identifier." + } + } } + }, + "required": [ + "type", + "action" + ] } -} \ No newline at end of file + } +} diff --git a/schemas/v0.1/eep-registry.json b/schemas/v0.1/eep-registry.json index 5d5b0ea..f68d83d 100644 --- a/schemas/v0.1/eep-registry.json +++ b/schemas/v0.1/eep-registry.json @@ -1,221 +1,221 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/eep-registry.json", - "title": "EEP Registry Federation Manifest", - "description": "Served at /.well-known/eep-registry.json. Declares that this domain operates a federated EEP registry. Used by agents to verify registry trust, and by eep.dev to issue Federation Credentials. (§4.5 Registry Federation, Whitepaper).", - "type": "object", - "required": [ - "did", - "registry_name", - "scope", - "conformance_tier_required", - "federation_credential_url" - ], - "additionalProperties": false, - "properties": { - "did": { - "type": "string", - "description": "DID of this registry operator organization.", - "pattern": "^did:[a-z0-9]+:.+$", - "examples": [ - "did:web:eep.eu" + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/eep-registry.json", + "title": "EEP Registry Federation Manifest", + "description": "Served at /.well-known/eep-registry.json. Declares that this domain operates a federated EEP registry. Used by agents to verify registry trust, and by eep.dev to issue Federation Credentials. (\u00a74.5 Registry Federation, Whitepaper).", + "type": "object", + "required": [ + "did", + "registry_name", + "scope", + "conformance_tier_required", + "federation_credential_url" + ], + "additionalProperties": false, + "properties": { + "did": { + "type": "string", + "description": "DID of this registry operator organization.", + "pattern": "^did:[a-z0-9]+:.+$", + "examples": [ + "did:web:eep.eu" + ] + }, + "registry_name": { + "type": "string", + "description": "Human-readable name for this registry.", + "maxLength": 128, + "examples": [ + "EEP European Financial Registry", + "EEP Health Sector Registry" + ] + }, + "registry_url": { + "type": "string", + "format": "uri", + "description": "Base URL of this registry's API.", + "examples": [ + "https://registry.eep.eu" + ] + }, + "scope": { + "type": "object", + "description": "Scope of entities this registry covers.", + "additionalProperties": false, + "properties": { + "geography": { + "type": "array", + "description": "ISO 3166-1 alpha-2 country codes or region strings this registry covers.", + "items": { + "type": "string" + }, + "examples": [ + [ + "EU", + "DE", + "FR" ] + ] }, - "registry_name": { - "type": "string", - "description": "Human-readable name for this registry.", - "maxLength": 128, - "examples": [ - "EEP European Financial Registry", - "EEP Health Sector Registry" + "sectors": { + "type": "array", + "description": "Industry sector identifiers this registry specializes in.", + "items": { + "type": "string" + }, + "examples": [ + [ + "financial_services", + "healthcare", + "supply_chain" ] + ] }, - "registry_url": { - "type": "string", - "format": "uri", - "description": "Base URL of this registry's API.", - "examples": [ - "https://registry.eep.eu" - ] - }, - "scope": { - "type": "object", - "description": "Scope of entities this registry covers.", - "additionalProperties": false, - "properties": { - "geography": { - "type": "array", - "description": "ISO 3166-1 alpha-2 country codes or region strings this registry covers.", - "items": { - "type": "string" - }, - "examples": [ - [ - "EU", - "DE", - "FR" - ] - ] - }, - "sectors": { - "type": "array", - "description": "Industry sector identifiers this registry specializes in.", - "items": { - "type": "string" - }, - "examples": [ - [ - "financial_services", - "healthcare", - "supply_chain" - ] - ] - }, - "capabilities": { - "type": "array", - "description": "EEP gate types or capability categories this registry validates.", - "items": { - "type": "string" - } - } - } - }, - "trust_criteria": { - "type": "object", - "description": "Describes the trust verification methodology this registry applies to registrants.", - "additionalProperties": false, - "properties": { - "did_verification": { - "type": "boolean", - "description": "Whether registrants must prove DID ownership.", - "default": true - }, - "manifest_consistency_check": { - "type": "boolean", - "description": "Whether registrant /.well-known/eep.json is validated for consistency.", - "default": true - }, - "additional_checks": { - "type": "array", - "items": { - "type": "string" - }, - "examples": [ - [ - "eidas_identity_verification", - "financial_license_check" - ] - ] - } - } - }, - "conformance_tier_required": { - "type": "string", - "description": "Minimum EEP conformance tier required for entities to be listed in this registry. Per Whitepaper §10.2: Core (Layer 1 + SSE), Standard (Core + Webhooks + credential/payment gates), Full (Standard + WS + commerce + agreement + data_request + session). No other tiers are defined.", - "enum": [ - "Core", - "Standard", - "Full" - ] - }, - "federation_credential_url": { - "type": "string", - "format": "uri", - "description": "URL where this registry's EEP Federation Credential (issued by eep.dev) can be fetched and verified by agents.", - "examples": [ - "https://eep.eu/.well-known/eep-federation-credential.json" - ] + "capabilities": { + "type": "array", + "description": "EEP gate types or capability categories this registry validates.", + "items": { + "type": "string" + } + } + } + }, + "trust_criteria": { + "type": "object", + "description": "Describes the trust verification methodology this registry applies to registrants.", + "additionalProperties": false, + "properties": { + "did_verification": { + "type": "boolean", + "description": "Whether registrants must prove DID ownership.", + "default": true }, - "cross_registry_resolution_url": { - "type": "string", - "format": "uri", - "description": "API endpoint implementing cross-registry resolution. When an entity is not found in this registry, queries peer registries.", - "examples": [ - "https://registry.eep.eu/api/resolve" - ] + "manifest_consistency_check": { + "type": "boolean", + "description": "Whether registrant /.well-known/eep.json is validated for consistency.", + "default": true }, - "eep_version": { - "type": "string", - "description": "EEP protocol version this registry speaks.", - "examples": [ - "0.1", - "1.0" + "additional_checks": { + "type": "array", + "items": { + "type": "string" + }, + "examples": [ + [ + "eidas_identity_verification", + "financial_license_check" ] + ] + } + } + }, + "conformance_tier_required": { + "type": "string", + "description": "Minimum EEP conformance tier required for entities to be listed in this registry. Per Whitepaper \u00a710.2: Core (Layer 1 + SSE), Standard (Core + Webhooks + credential/payment gates), Full (Standard + WS + commerce + agreement + data_request + session). No other tiers are defined.", + "enum": [ + "Core", + "Standard", + "Full" + ] + }, + "federation_credential_url": { + "type": "string", + "format": "uri", + "description": "URL where this registry's EEP Federation Credential (issued by eep.dev) can be fetched and verified by agents.", + "examples": [ + "https://eep.eu/.well-known/eep-federation-credential.json" + ] + }, + "cross_registry_resolution_url": { + "type": "string", + "format": "uri", + "description": "API endpoint implementing cross-registry resolution. When an entity is not found in this registry, queries peer registries.", + "examples": [ + "https://registry.eep.eu/api/resolve" + ] + }, + "eep_version": { + "type": "string", + "description": "EEP protocol version this registry speaks.", + "examples": [ + "0.1", + "1.0" + ] + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 datetime of last manifest update." + }, + "economics": { + "type": "object", + "description": "Machine-readable sustainability and pricing signals for registry APIs (SPEC \u00a712.6.1).", + "additionalProperties": false, + "properties": { + "registration_fee": { + "type": "object", + "additionalProperties": false, + "properties": { + "amount": { + "type": "number", + "minimum": 0 + }, + "currency": { + "type": "string", + "pattern": "^[A-Z]{3}$" + }, + "per": { + "type": "string", + "enum": [ + "once", + "year", + "month" + ] + } + } }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "ISO 8601 datetime of last manifest update." + "query_quota": { + "type": "object", + "additionalProperties": false, + "properties": { + "free_requests_per_day": { + "type": "integer", + "minimum": 0 + }, + "paid_tier_url": { + "type": "string", + "format": "uri" + } + } }, - "economics": { - "type": "object", - "description": "Machine-readable sustainability and pricing signals for registry APIs (SPEC §12.6.1).", - "additionalProperties": false, - "properties": { - "registration_fee": { - "type": "object", - "additionalProperties": false, - "properties": { - "amount": { - "type": "number", - "minimum": 0 - }, - "currency": { - "type": "string", - "pattern": "^[A-Z]{3}$" - }, - "per": { - "type": "string", - "enum": [ - "once", - "year", - "month" - ] - } - } - }, - "query_quota": { - "type": "object", - "additionalProperties": false, - "properties": { - "free_requests_per_day": { - "type": "integer", - "minimum": 0 - }, - "paid_tier_url": { - "type": "string", - "format": "uri" - } - } - }, - "staking_or_challenge": { - "type": "object", - "additionalProperties": false, - "properties": { - "mode": { - "type": "string", - "enum": [ - "none", - "micro_stake", - "proof_of_payment", - "proof_of_work_challenge" - ] - }, - "min_amount": { - "type": "number", - "minimum": 0 - }, - "currency": { - "type": "string", - "pattern": "^[A-Z]{3}$" - }, - "challenge_endpoint": { - "type": "string", - "format": "uri" - } - } - } + "staking_or_challenge": { + "type": "object", + "additionalProperties": false, + "properties": { + "mode": { + "type": "string", + "enum": [ + "none", + "micro_stake", + "proof_of_payment", + "proof_of_work_challenge" + ] + }, + "min_amount": { + "type": "number", + "minimum": 0 + }, + "currency": { + "type": "string", + "pattern": "^[A-Z]{3}$" + }, + "challenge_endpoint": { + "type": "string", + "format": "uri" } + } } + } } -} \ No newline at end of file + } +} diff --git a/schemas/v0.1/event.envelope.json b/schemas/v0.1/event.envelope.json index 8f2f0df..91af690 100644 --- a/schemas/v0.1/event.envelope.json +++ b/schemas/v0.1/event.envelope.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://eep.dev/schemas/v0.1/event.envelope.json", "title": "EEP Event Envelope", "description": "Schema for a valid EEP/CloudEvents v1.0.2 event. All EEP events MUST conform to this schema. This is a superset of the CloudEvents v1.0.2 envelope with EEP-specific extensions. See SPECIFICATION.md \u00a713 for the canonical event type registry.", diff --git a/schemas/v0.1/gate.402-response.json b/schemas/v0.1/gate.402-response.json index 0730727..c46564b 100644 --- a/schemas/v0.1/gate.402-response.json +++ b/schemas/v0.1/gate.402-response.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://eep.dev/schemas/v0.1/gate.402-response.json", "title": "EEP Access Restriction Response (402)", "description": "Schema for the HTTP 402 response body returned when an agent requests a resource that requires a higher tier. The response is machine-readable so agents can programmatically determine what requirements to satisfy. Served as `application/problem+json` per RFC 9457; the EEP-specific members below are problem extension members.", diff --git a/schemas/v0.1/gate.403-response.json b/schemas/v0.1/gate.403-response.json index 283461b..b4bde97 100644 --- a/schemas/v0.1/gate.403-response.json +++ b/schemas/v0.1/gate.403-response.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://eep.dev/schemas/v0.1/gate.403-response.json", "title": "EEP Gate 403 Forbidden Response", "description": "Returned when a credential, agreement, identity, or allowlist gate prevents access Served as `application/problem+json` per RFC 9457; the EEP-specific members below are problem extension members.", diff --git a/schemas/v0.1/gate.429-response.json b/schemas/v0.1/gate.429-response.json index 58a224b..3c4089e 100644 --- a/schemas/v0.1/gate.429-response.json +++ b/schemas/v0.1/gate.429-response.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://eep.dev/schemas/v0.1/gate.429-response.json", "title": "EEP Rate-Limit Response (429)", "description": "Schema for HTTP 429 Too Many Requests response body returned by EEP publishers implementing DID-based token-bucket rate limiting. See SPECIFICATION.md \u00a73.4.6 and Whitepaper \u00a710.5. Served as `application/problem+json` per RFC 9457; the EEP-specific members below are problem extension members.", diff --git a/schemas/v0.1/gate.451-response.json b/schemas/v0.1/gate.451-response.json index b137183..fba3d90 100644 --- a/schemas/v0.1/gate.451-response.json +++ b/schemas/v0.1/gate.451-response.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://eep.dev/schemas/v0.1/gate.451-response.json", "title": "EEP Gate 451 Legally Restricted Response", "description": "Returned when a resource is unavailable for legal reasons (EU AI Act, DORA, judicial orders, etc.) Served as `application/problem+json` per RFC 9457; the EEP-specific members below are problem extension members.", diff --git a/schemas/v0.1/gate.config.json b/schemas/v0.1/gate.config.json index 1c270bb..ea83556 100644 --- a/schemas/v0.1/gate.config.json +++ b/schemas/v0.1/gate.config.json @@ -1,620 +1,620 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/gate.config.json", - "title": "EEP Gate Configuration", - "description": "Schema for an entity's gate configuration. Gates define access tiers with customizable requirements. Tier names, requirement combinations, and access patterns are fully entity-defined. The protocol defines requirement TYPES, not VALUES.", - "type": "object", - "required": [ - "default_tier", - "tiers" - ], - "additionalProperties": false, - "properties": { - "default_tier": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/gate.config.json", + "title": "EEP Gate Configuration", + "description": "Schema for an entity's gate configuration. Gates define access tiers with customizable requirements. Tier names, requirement combinations, and access patterns are fully entity-defined. The protocol defines requirement TYPES, not VALUES.", + "type": "object", + "required": [ + "default_tier", + "tiers" + ], + "additionalProperties": false, + "properties": { + "default_tier": { + "type": "string", + "description": "The tier applied when no gate proofs are provided. This tier MUST exist in the tiers map and MUST have an empty requirements array (publicly accessible).", + "pattern": "^[a-z][a-z0-9_]{0,31}$", + "examples": [ + "public", + "free", + "open" + ] + }, + "tiers": { + "type": "object", + "description": "Entity-defined tiers. Keys are tier identifiers (lowercase alphanumeric + underscores, max 32 chars). An entity can define any tier names it wants.", + "minProperties": 1, + "maxProperties": 20, + "patternProperties": { + "^[a-z][a-z0-9_]{0,31}$": { + "$ref": "#/$defs/tier" + } + }, + "additionalProperties": false + }, + "fallback_behavior": { + "type": "string", + "description": "What happens when a request doesn't match any tier. 'restrict' returns 402; 'default' falls back to default_tier silently.", + "enum": [ + "restrict", + "default" + ], + "default": "restrict" + } + }, + "$defs": { + "tier": { + "type": "object", + "required": [ + "requirements", + "access" + ], + "additionalProperties": false, + "properties": { + "label": { + "type": "string", + "description": "Human-readable tier name for display (entity-defined).", + "maxLength": 128, + "examples": [ + "Academic Access", + "Pro Plan", + "VIP Members" + ] + }, + "description": { + "type": "string", + "description": "Optional description of what this tier provides.", + "maxLength": 512 + }, + "requirements": { + "type": "array", + "description": "List of requirements that MUST ALL be satisfied (AND logic) to access this tier. Empty array means no requirements (public access).", + "maxItems": 10, + "items": { + "$ref": "#/$defs/requirement" + } + }, + "access": { + "type": "array", + "description": "Resource patterns this tier grants access to. Supports wildcard suffix: 'profile.*' matches all profile fields. '*' matches everything.", + "minItems": 1, + "maxItems": 100, + "items": { "type": "string", - "description": "The tier applied when no gate proofs are provided. This tier MUST exist in the tiers map and MUST have an empty requirements array (publicly accessible).", - "pattern": "^[a-z][a-z0-9_]{0,31}$", + "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*(\\.(\\*|[a-z][a-z0-9_]*))?$|^\\*$", "examples": [ - "public", - "free", - "open" + "profile.summary", + "profile.*", + "events.public", + "content.pages.*", + "*" ] + } }, - "tiers": { - "type": "object", - "description": "Entity-defined tiers. Keys are tier identifiers (lowercase alphanumeric + underscores, max 32 chars). An entity can define any tier names it wants.", - "minProperties": 1, - "maxProperties": 20, - "patternProperties": { - "^[a-z][a-z0-9_]{0,31}$": { - "$ref": "#/definitions/tier" - } - }, - "additionalProperties": false + "rate_limit": { + "$ref": "#/$defs/rate_limit" }, - "fallback_behavior": { - "type": "string", - "description": "What happens when a request doesn't match any tier. 'restrict' returns 402; 'default' falls back to default_tier silently.", - "enum": [ - "restrict", - "default" - ], - "default": "restrict" + "metadata": { + "type": "object", + "description": "Optional entity-defined metadata for this tier.", + "additionalProperties": true, + "maxProperties": 20 } + } }, - "definitions": { - "tier": { - "type": "object", - "required": [ - "requirements", - "access" - ], - "additionalProperties": false, + "requirement": { + "type": "object", + "required": [ + "type" + ], + "description": "A single requirement. The 'type' field determines which additional fields are expected. Standard types are defined below; custom types use the 'x-' prefix.", + "properties": { + "type": { + "type": "string", + "description": "Requirement type identifier. Standard types: payment, trust, identity, connection, credential, capability, allowlist, reciprocal, data_request, agreement, combined. Custom types: x-{name}.", + "pattern": "^(payment|trust|identity|connection|credential|capability|allowlist|reciprocal|data_request|agreement|combined|x-[a-z][a-z0-9_-]*)$" + } + }, + "allOf": [ + { + "if": { "properties": { - "label": { - "type": "string", - "description": "Human-readable tier name for display (entity-defined).", - "maxLength": 128, - "examples": [ - "Academic Access", - "Pro Plan", - "VIP Members" - ] + "type": { + "const": "payment" + } + } + }, + "then": { + "properties": { + "type": true, + "amount": { + "type": "number", + "description": "Payment amount. Must be positive.", + "exclusiveMinimum": 0 + }, + "currency": { + "type": "string", + "description": "ISO 4217 currency code (lowercase).", + "pattern": "^[a-z]{3}$", + "examples": [ + "usd", + "eur", + "gbp" + ] + }, + "per": { + "type": "string", + "description": "Billing period.", + "enum": [ + "request", + "hour", + "day", + "week", + "month", + "year", + "once" + ] + }, + "payment_methods": { + "type": "array", + "description": "URLs or identifiers for accepted payment methods. Protocol-agnostic: can be Stripe checkout URLs, crypto addresses, or any other endpoint.", + "items": { + "type": "string" }, - "description": { + "maxItems": 10 + }, + "x402": { + "type": "object", + "description": "Native x402 protocol payment rail configuration (ref27 \u2014 https://x402.org).", + "additionalProperties": false, + "properties": { + "enabled": { + "type": "boolean" + }, + "facilitator_url": { "type": "string", - "description": "Optional description of what this tier provides.", - "maxLength": 512 - }, - "requirements": { - "type": "array", - "description": "List of requirements that MUST ALL be satisfied (AND logic) to access this tier. Empty array means no requirements (public access).", - "maxItems": 10, - "items": { - "$ref": "#/definitions/requirement" - } - }, - "access": { + "format": "uri" + }, + "payment_rails": { "type": "array", - "description": "Resource patterns this tier grants access to. Supports wildcard suffix: 'profile.*' matches all profile fields. '*' matches everything.", - "minItems": 1, - "maxItems": 100, "items": { - "type": "string", - "pattern": "^[a-z][a-z0-9_]*(\\.[a-z][a-z0-9_]*)*(\\.(\\*|[a-z][a-z0-9_]*))?$|^\\*$", - "examples": [ - "profile.summary", - "profile.*", - "events.public", - "content.pages.*", - "*" - ] - } - }, - "rate_limit": { - "$ref": "#/definitions/rate_limit" + "type": "string" + }, + "examples": [ + [ + "x402/usdc", + "x402/eth" + ] + ] + }, + "network": { + "type": "string", + "examples": [ + "base", + "ethereum", + "polygon" + ] + } }, - "metadata": { - "type": "object", - "description": "Optional entity-defined metadata for this tier.", - "additionalProperties": true, - "maxProperties": 20 - } + "required": [ + "enabled" + ] + } + }, + "required": [ + "type", + "amount", + "currency", + "per" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "trust" + } } + }, + "then": { + "properties": { + "type": true, + "min_score": { + "type": "integer", + "description": "Minimum trust score required (0-100).", + "minimum": 0, + "maximum": 100 + } + }, + "required": [ + "type", + "min_score" + ], + "additionalProperties": false + } }, - "requirement": { - "type": "object", + { + "if": { + "properties": { + "type": { + "const": "identity" + } + } + }, + "then": { + "properties": { + "type": true, + "method": { + "type": "string", + "description": "Required identity verification method.", + "enum": [ + "did_verified", + "email_verified", + "domain_verified", + "kyc", + "any" + ] + } + }, "required": [ - "type" + "type", + "method" ], - "description": "A single requirement. The 'type' field determines which additional fields are expected. Standard types are defined below; custom types use the 'x-' prefix.", + "additionalProperties": false + } + }, + { + "if": { "properties": { - "type": { - "type": "string", - "description": "Requirement type identifier. Standard types: payment, trust, identity, connection, credential, capability, allowlist, reciprocal, data_request, agreement, combined. Custom types: x-{name}.", - "pattern": "^(payment|trust|identity|connection|credential|capability|allowlist|reciprocal|data_request|agreement|combined|x-[a-z][a-z0-9_-]*)$" - } + "type": { + "const": "connection" + } + } + }, + "then": { + "properties": { + "type": true, + "relation": { + "type": "string", + "description": "Required social connection type.", + "enum": [ + "follower", + "following", + "mutual", + "any" + ] + } }, - "allOf": [ - { - "if": { - "properties": { - "type": { - "const": "payment" - } - } - }, - "then": { - "properties": { - "type": true, - "amount": { - "type": "number", - "description": "Payment amount. Must be positive.", - "exclusiveMinimum": 0 - }, - "currency": { - "type": "string", - "description": "ISO 4217 currency code (lowercase).", - "pattern": "^[a-z]{3}$", - "examples": [ - "usd", - "eur", - "gbp" - ] - }, - "per": { - "type": "string", - "description": "Billing period.", - "enum": [ - "request", - "hour", - "day", - "week", - "month", - "year", - "once" - ] - }, - "payment_methods": { - "type": "array", - "description": "URLs or identifiers for accepted payment methods. Protocol-agnostic: can be Stripe checkout URLs, crypto addresses, or any other endpoint.", - "items": { - "type": "string" - }, - "maxItems": 10 - }, - "x402": { - "type": "object", - "description": "Native x402 protocol payment rail configuration (ref27 — https://x402.org).", - "additionalProperties": false, - "properties": { - "enabled": { - "type": "boolean" - }, - "facilitator_url": { - "type": "string", - "format": "uri" - }, - "payment_rails": { - "type": "array", - "items": { - "type": "string" - }, - "examples": [ - [ - "x402/usdc", - "x402/eth" - ] - ] - }, - "network": { - "type": "string", - "examples": [ - "base", - "ethereum", - "polygon" - ] - } - }, - "required": [ - "enabled" - ] - } - }, - "required": [ - "type", - "amount", - "currency", - "per" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "trust" - } - } - }, - "then": { - "properties": { - "type": true, - "min_score": { - "type": "integer", - "description": "Minimum trust score required (0-100).", - "minimum": 0, - "maximum": 100 - } - }, - "required": [ - "type", - "min_score" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "identity" - } - } - }, - "then": { - "properties": { - "type": true, - "method": { - "type": "string", - "description": "Required identity verification method.", - "enum": [ - "did_verified", - "email_verified", - "domain_verified", - "kyc", - "any" - ] - } - }, - "required": [ - "type", - "method" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "connection" - } - } - }, - "then": { - "properties": { - "type": true, - "relation": { - "type": "string", - "description": "Required social connection type.", - "enum": [ - "follower", - "following", - "mutual", - "any" - ] - } - }, - "required": [ - "type", - "relation" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "credential" - } - } - }, - "then": { - "properties": { - "type": true, - "credential_type": { - "type": "string", - "description": "Required W3C Verifiable Credential type.", - "examples": [ - "AcademicAffiliation", - "ProfessionalLicense", - "GovernmentID" - ] - }, - "issuer": { - "type": "string", - "description": "Optional: required credential issuer DID or domain.", - "examples": [ - "did:web:university.edu" - ] - }, - "accepted_formats": { - "type": "array", - "description": "Accepted credential formats.", - "items": { - "type": "string", - "enum": [ - "jwt_vc", - "ldp_vc", - "sd_jwt_vc" - ] - }, - "default": [ - "jwt_vc" - ] - } - }, - "required": [ - "type", - "credential_type" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "capability" - } - } - }, - "then": { - "properties": { - "type": true, - "required_capabilities": { - "type": "array", - "description": "Agent must declare these capabilities.", - "items": { - "type": "string" - }, - "minItems": 1 - } - }, - "required": [ - "type", - "required_capabilities" - ], - "additionalProperties": false - } + "required": [ + "type", + "relation" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "credential" + } + } + }, + "then": { + "properties": { + "type": true, + "credential_type": { + "type": "string", + "description": "Required W3C Verifiable Credential type.", + "examples": [ + "AcademicAffiliation", + "ProfessionalLicense", + "GovernmentID" + ] + }, + "issuer": { + "type": "string", + "description": "Optional: required credential issuer DID or domain.", + "examples": [ + "did:web:university.edu" + ] + }, + "accepted_formats": { + "type": "array", + "description": "Accepted credential formats.", + "items": { + "type": "string", + "enum": [ + "jwt_vc", + "ldp_vc", + "sd_jwt_vc" + ] }, - { - "if": { - "properties": { - "type": { - "const": "allowlist" - } - } - }, - "then": { - "properties": { - "type": true, - "dids": { - "type": "array", - "description": "Explicit list of allowed DIDs.", - "items": { - "type": "string" - }, - "minItems": 1, - "maxItems": 1000 - } - }, - "required": [ - "type", - "dids" - ], - "additionalProperties": false - } + "default": [ + "jwt_vc" + ] + } + }, + "required": [ + "type", + "credential_type" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "capability" + } + } + }, + "then": { + "properties": { + "type": true, + "required_capabilities": { + "type": "array", + "description": "Agent must declare these capabilities.", + "items": { + "type": "string" }, - { - "if": { - "properties": { - "type": { - "const": "reciprocal" - } - } - }, - "then": { - "properties": { - "type": true, - "access_level": { - "type": "string", - "description": "The minimum access level the requesting entity must grant back to this entity.", - "examples": [ - "profile.*", - "*" - ] - } - }, - "required": [ - "type", - "access_level" - ], - "additionalProperties": false - } + "minItems": 1 + } + }, + "required": [ + "type", + "required_capabilities" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "allowlist" + } + } + }, + "then": { + "properties": { + "type": true, + "dids": { + "type": "array", + "description": "Explicit list of allowed DIDs.", + "items": { + "type": "string" }, - { - "if": { - "properties": { - "type": { - "const": "data_request" - } - } + "minItems": 1, + "maxItems": 1000 + } + }, + "required": [ + "type", + "dids" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "reciprocal" + } + } + }, + "then": { + "properties": { + "type": true, + "access_level": { + "type": "string", + "description": "The minimum access level the requesting entity must grant back to this entity.", + "examples": [ + "profile.*", + "*" + ] + } + }, + "required": [ + "type", + "access_level" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "data_request" + } + } + }, + "then": { + "properties": { + "type": true, + "requested_claims": { + "type": "array", + "description": "List of specific claim types requested. Broad identity bundles are a protocol violation; each entry must name exactly one claim.", + "minItems": 1, + "maxItems": 20, + "items": { + "type": "object", + "required": [ + "claim", + "purpose", + "retention_days" + ], + "additionalProperties": false, + "properties": { + "claim": { + "type": "string", + "description": "Specific claim identifier (e.g. org_type, use_case_category).", + "examples": [ + "org_type", + "use_case_category", + "owner_email" + ] }, - "then": { - "properties": { - "type": true, - "requested_claims": { - "type": "array", - "description": "List of specific claim types requested. Broad identity bundles are a protocol violation; each entry must name exactly one claim.", - "minItems": 1, - "maxItems": 20, - "items": { - "type": "object", - "required": [ - "claim", - "purpose", - "retention_days" - ], - "additionalProperties": false, - "properties": { - "claim": { - "type": "string", - "description": "Specific claim identifier (e.g. org_type, use_case_category).", - "examples": [ - "org_type", - "use_case_category", - "owner_email" - ] - }, - "purpose": { - "type": "string", - "description": "W3C Data Privacy Vocabulary (DPV) URI declaring processing purpose.", - "pattern": "^dpv:[A-Z][a-zA-Z]+$", - "examples": [ - "dpv:ResearchAndDevelopment", - "dpv:ServiceProvision", - "dpv:LegalObligation" - ] - }, - "retention_days": { - "type": "integer", - "description": "Days publisher will retain this claim. Binding commitment; must be honored.", - "minimum": 0, - "maximum": 3650 - }, - "shareable": { - "type": "boolean", - "description": "Whether publisher may share this claim with third parties.", - "default": false - } - } - } - }, - "policy_url": { - "type": "string", - "format": "uri", - "description": "URL to the publisher's full privacy policy document." - }, - "policy_hash": { - "type": "string", - "description": "SHA-256 hash of the policy document at policy_url (sha256:hex).", - "pattern": "^sha256:[a-f0-9]{64}$" - } - }, - "required": [ - "type", - "requested_claims" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "agreement" - } - } + "purpose": { + "type": "string", + "description": "W3C Data Privacy Vocabulary (DPV) URI declaring processing purpose.", + "pattern": "^dpv:[A-Z][a-zA-Z]+$", + "examples": [ + "dpv:ResearchAndDevelopment", + "dpv:ServiceProvision", + "dpv:LegalObligation" + ] }, - "then": { - "properties": { - "type": true, - "document_hash": { - "type": "string", - "description": "SHA-256 hash of the license/agreement document (sha256:hex). The agent must sign this hash.", - "pattern": "^sha256:[a-f0-9]{64}$" - }, - "document_url": { - "type": "string", - "format": "uri", - "description": "URL where the agent can fetch the agreement document." - }, - "document_title": { - "type": "string", - "description": "Human-readable title of the agreement (e.g. 'Creative Commons NC 4.0')." - }, - "signature_algo": { - "type": "string", - "description": "Required signing algorithm.", - "enum": [ - "EdDSA", - "ES256K" - ], - "default": "EdDSA" - } - }, - "required": [ - "type", - "document_hash", - "document_url" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "combined" - } - } + "retention_days": { + "type": "integer", + "description": "Days publisher will retain this claim. Binding commitment; must be honored.", + "minimum": 0, + "maximum": 3650 }, - "then": { - "properties": { - "type": true, - "combine_mode": { - "type": "string", - "description": "all = AND (every nested requirement); any = OR (at least one nested requirement).", - "enum": [ - "all", - "any" - ] - }, - "requirements": { - "type": "array", - "description": "Nested gate requirements verified atomically as one bundle.", - "minItems": 2, - "maxItems": 10, - "items": { - "$ref": "#/definitions/requirement" - } - }, - "recommended_collection_order": { - "type": "array", - "description": "Optional hint listing requirement types in the order operators should collect proofs (e.g. agreement before payment).", - "items": { - "type": "string" - }, - "maxItems": 10 - } - }, - "required": [ - "type", - "combine_mode", - "requirements" - ], - "additionalProperties": false + "shareable": { + "type": "boolean", + "description": "Whether publisher may share this claim with third parties.", + "default": false } + } } - ] + }, + "policy_url": { + "type": "string", + "format": "uri", + "description": "URL to the publisher's full privacy policy document." + }, + "policy_hash": { + "type": "string", + "description": "SHA-256 hash of the policy document at policy_url (sha256:hex).", + "pattern": "^sha256:[a-f0-9]{64}$" + } + }, + "required": [ + "type", + "requested_claims" + ], + "additionalProperties": false + } }, - "rate_limit": { - "type": "object", - "description": "Optional per-tier rate limits. Overrides platform defaults for this tier.", - "additionalProperties": false, + { + "if": { "properties": { - "requests_per_minute": { - "type": "integer", - "minimum": 1 - }, - "requests_per_hour": { - "type": "integer", - "minimum": 1 - }, - "requests_per_day": { - "type": "integer", - "minimum": 1 - }, - "concurrent_connections": { - "type": "integer", - "minimum": 1, - "maximum": 100 - } + "type": { + "const": "agreement" + } } + }, + "then": { + "properties": { + "type": true, + "document_hash": { + "type": "string", + "description": "SHA-256 hash of the license/agreement document (sha256:hex). The agent must sign this hash.", + "pattern": "^sha256:[a-f0-9]{64}$" + }, + "document_url": { + "type": "string", + "format": "uri", + "description": "URL where the agent can fetch the agreement document." + }, + "document_title": { + "type": "string", + "description": "Human-readable title of the agreement (e.g. 'Creative Commons NC 4.0')." + }, + "signature_algo": { + "type": "string", + "description": "Required signing algorithm.", + "enum": [ + "EdDSA", + "ES256K" + ], + "default": "EdDSA" + } + }, + "required": [ + "type", + "document_hash", + "document_url" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "combined" + } + } + }, + "then": { + "properties": { + "type": true, + "combine_mode": { + "type": "string", + "description": "all = AND (every nested requirement); any = OR (at least one nested requirement).", + "enum": [ + "all", + "any" + ] + }, + "requirements": { + "type": "array", + "description": "Nested gate requirements verified atomically as one bundle.", + "minItems": 2, + "maxItems": 10, + "items": { + "$ref": "#/$defs/requirement" + } + }, + "recommended_collection_order": { + "type": "array", + "description": "Optional hint listing requirement types in the order operators should collect proofs (e.g. agreement before payment).", + "items": { + "type": "string" + }, + "maxItems": 10 + } + }, + "required": [ + "type", + "combine_mode", + "requirements" + ], + "additionalProperties": false + } + } + ] + }, + "rate_limit": { + "type": "object", + "description": "Optional per-tier rate limits. Overrides platform defaults for this tier.", + "additionalProperties": false, + "properties": { + "requests_per_minute": { + "type": "integer", + "minimum": 1 + }, + "requests_per_hour": { + "type": "integer", + "minimum": 1 + }, + "requests_per_day": { + "type": "integer", + "minimum": 1 + }, + "concurrent_connections": { + "type": "integer", + "minimum": 1, + "maximum": 100 } + } } -} \ No newline at end of file + } +} diff --git a/schemas/v0.1/gate.proof.json b/schemas/v0.1/gate.proof.json index ded2d4d..5b6c1b4 100644 --- a/schemas/v0.1/gate.proof.json +++ b/schemas/v0.1/gate.proof.json @@ -1,540 +1,540 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/gate.proof.json", - "title": "EEP Gate Proof", - "description": "Schema for gate proofs submitted by agents to satisfy tier requirements. Each proof corresponds to a requirement type. Structural validation happens at the protocol level; semantic validation (e.g., verifying a payment token is actually valid) is the responsibility of the implementing platform via the ProofVerifier interface.", - "type": "object", - "required": [ - "gate_proofs" - ], - "additionalProperties": false, - "properties": { - "gate_proofs": { - "type": "array", - "description": "Array of proof objects. Each proof satisfies one requirement. Multiple proofs can be provided to satisfy multi-requirement tiers.", - "minItems": 1, - "maxItems": 10, - "items": { - "$ref": "#/definitions/proof" - } + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/gate.proof.json", + "title": "EEP Gate Proof", + "description": "Schema for gate proofs submitted by agents to satisfy tier requirements. Each proof corresponds to a requirement type. Structural validation happens at the protocol level; semantic validation (e.g., verifying a payment token is actually valid) is the responsibility of the implementing platform via the ProofVerifier interface.", + "type": "object", + "required": [ + "gate_proofs" + ], + "additionalProperties": false, + "properties": { + "gate_proofs": { + "type": "array", + "description": "Array of proof objects. Each proof satisfies one requirement. Multiple proofs can be provided to satisfy multi-requirement tiers.", + "minItems": 1, + "maxItems": 10, + "items": { + "$ref": "#/$defs/proof" + } + } + }, + "$defs": { + "proof": { + "type": "object", + "required": [ + "type" + ], + "description": "A single proof. Structure varies by type. The 'type' field must match a requirement type from the gate configuration.", + "properties": { + "type": { + "type": "string", + "description": "Proof type, must match the requirement type it satisfies.", + "pattern": "^(payment|trust|identity|connection|credential|capability|allowlist|reciprocal|proof_of_intent|data_request|agreement|x-[a-z][a-z0-9_-]*)$" + }, + "issued_at": { + "type": "string", + "description": "When this proof was issued (ISO 8601). Used for freshness validation.", + "format": "date-time" + }, + "expires_at": { + "type": "string", + "description": "When this proof expires (ISO 8601). Null or absent means the proof does not expire.", + "format": "date-time" + }, + "nonce": { + "type": "string", + "description": "Optional nonce to prevent replay attacks.", + "maxLength": 128 } - }, - "definitions": { - "proof": { - "type": "object", - "required": [ - "type" - ], - "description": "A single proof. Structure varies by type. The 'type' field must match a requirement type from the gate configuration.", + }, + "allOf": [ + { + "if": { "properties": { - "type": { + "type": { + "const": "payment" + } + } + }, + "then": { + "properties": { + "type": true, + "issued_at": true, + "expires_at": true, + "nonce": true, + "token": { + "type": "string", + "description": "Payment proof token from the payment provider. Opaque to the protocol.", + "minLength": 1, + "maxLength": 4096 + }, + "provider": { + "type": "string", + "description": "URL or identifier of the payment provider that issued this token.", + "examples": [ + "https://pay.example.com", + "https://checkout.stripe.com" + ] + }, + "tier": { + "type": "string", + "description": "The tier this payment was made for." + }, + "chain": { + "type": "string", + "description": "Blockchain network name used for on-chain payment. MUST match one of the publisher's declared payment_networks[].chain values. Required when tx_hash is present. (G27)", + "examples": [ + "solana", + "base", + "ethereum", + "polygon" + ] + }, + "tx_hash": { + "type": "string", + "description": "On-chain transaction hash of the payment. The publisher MUST verify on-chain finality (min_confirmations) before granting access. (G27)", + "pattern": "^(0x[0-9a-fA-F]{64}|[1-9A-HJ-NP-Za-km-z]{87,88})$", + "examples": [ + "0xabc123...def456", + "5KtmkVXLoWizHrUmLP1NkiGrmKa2Q2g3X5hk3pXHKGe3iY7tR1aSdfJk2bN" + ] + }, + "confirmations": { + "type": "integer", + "description": "Number of block confirmations at proof submission time. Publisher MUST verify this meets min_confirmations for the declared chain. (G27)", + "minimum": 0 + }, + "x402_payload": { + "type": "object", + "description": "x402 protocol EIP-712 payment payload. Mutually exclusive with token \u2014 use either token (traditional) or x402_payload (on-chain).", + "additionalProperties": false, + "required": [ + "payload", + "signature", + "network" + ], + "properties": { + "payload": { "type": "string", - "description": "Proof type, must match the requirement type it satisfies.", - "pattern": "^(payment|trust|identity|connection|credential|capability|allowlist|reciprocal|proof_of_intent|data_request|agreement|x-[a-z][a-z0-9_-]*)$" - }, - "issued_at": { + "description": "EIP-712 PaymentPayload JSON string", + "minLength": 1 + }, + "signature": { "type": "string", - "description": "When this proof was issued (ISO 8601). Used for freshness validation.", - "format": "date-time" - }, - "expires_at": { + "description": "Hex-encoded secp256k1 signature (0x-prefixed, 130+ hex chars)", + "pattern": "^0x[0-9a-fA-F]{128,}$" + }, + "network": { "type": "string", - "description": "When this proof expires (ISO 8601). Null or absent means the proof does not expire.", - "format": "date-time" - }, - "nonce": { + "description": "Blockchain network name", + "examples": [ + "base", + "ethereum", + "polygon" + ] + }, + "settlement_tx": { "type": "string", - "description": "Optional nonce to prevent replay attacks.", - "maxLength": 128 + "description": "On-chain transaction hash after settlement" + } } + } }, - "allOf": [ - { - "if": { - "properties": { - "type": { - "const": "payment" - } - } - }, - "then": { - "properties": { - "type": true, - "issued_at": true, - "expires_at": true, - "nonce": true, - "token": { - "type": "string", - "description": "Payment proof token from the payment provider. Opaque to the protocol.", - "minLength": 1, - "maxLength": 4096 - }, - "provider": { - "type": "string", - "description": "URL or identifier of the payment provider that issued this token.", - "examples": [ - "https://pay.example.com", - "https://checkout.stripe.com" - ] - }, - "tier": { - "type": "string", - "description": "The tier this payment was made for." - }, - "chain": { - "type": "string", - "description": "Blockchain network name used for on-chain payment. MUST match one of the publisher's declared payment_networks[].chain values. Required when tx_hash is present. (G27)", - "examples": [ - "solana", - "base", - "ethereum", - "polygon" - ] - }, - "tx_hash": { - "type": "string", - "description": "On-chain transaction hash of the payment. The publisher MUST verify on-chain finality (min_confirmations) before granting access. (G27)", - "pattern": "^(0x[0-9a-fA-F]{64}|[1-9A-HJ-NP-Za-km-z]{87,88})$", - "examples": [ - "0xabc123...def456", - "5KtmkVXLoWizHrUmLP1NkiGrmKa2Q2g3X5hk3pXHKGe3iY7tR1aSdfJk2bN" - ] - }, - "confirmations": { - "type": "integer", - "description": "Number of block confirmations at proof submission time. Publisher MUST verify this meets min_confirmations for the declared chain. (G27)", - "minimum": 0 - }, - "x402_payload": { - "type": "object", - "description": "x402 protocol EIP-712 payment payload. Mutually exclusive with token — use either token (traditional) or x402_payload (on-chain).", - "additionalProperties": false, - "required": [ - "payload", - "signature", - "network" - ], - "properties": { - "payload": { - "type": "string", - "description": "EIP-712 PaymentPayload JSON string", - "minLength": 1 - }, - "signature": { - "type": "string", - "description": "Hex-encoded secp256k1 signature (0x-prefixed, 130+ hex chars)", - "pattern": "^0x[0-9a-fA-F]{128,}$" - }, - "network": { - "type": "string", - "description": "Blockchain network name", - "examples": [ - "base", - "ethereum", - "polygon" - ] - }, - "settlement_tx": { - "type": "string", - "description": "On-chain transaction hash after settlement" - } - } - } - }, - "required": [ - "type" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "trust" - } - } - }, - "then": { - "properties": { - "type": true, - "issued_at": true, - "expires_at": true, - "nonce": true, - "self_attested": { - "type": "boolean", - "description": "If true, the subscriber claims their trust score meets the requirement. The publisher MUST verify this independently.", - "const": true - } - }, - "required": [ - "type", - "self_attested" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "identity" - } - } - }, - "then": { - "properties": { - "type": true, - "issued_at": true, - "expires_at": true, - "nonce": true, - "method": { - "type": "string", - "description": "The verification method used.", - "enum": [ - "did_verified", - "email_verified", - "domain_verified", - "kyc", - "any" - ] - }, - "evidence": { - "type": "string", - "description": "Verification evidence (e.g., a signed DID assertion, email verification token). Opaque to the protocol.", - "maxLength": 8192 - } - }, - "required": [ - "type", - "method" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "connection" - } - } - }, - "then": { - "properties": { - "type": true, - "issued_at": true, - "expires_at": true, - "nonce": true, - "subscriber_did": { - "type": "string", - "description": "The DID of the subscriber claiming the connection." - }, - "relation": { - "type": "string", - "description": "The claimed connection type.", - "enum": [ - "follower", - "following", - "mutual", - "any" - ] - } - }, - "required": [ - "type", - "subscriber_did" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "credential" - } - } - }, - "then": { - "properties": { - "type": true, - "issued_at": true, - "expires_at": true, - "nonce": true, - "credential": { - "type": "string", - "description": "The Verifiable Credential (encoded per the format field).", - "maxLength": 65536 - }, - "format": { - "type": "string", - "description": "Credential encoding format.", - "enum": [ - "jwt_vc", - "ldp_vc", - "sd_jwt_vc" - ], - "default": "jwt_vc" - } - }, - "required": [ - "type", - "credential", - "format" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "capability" - } - } - }, - "then": { - "properties": { - "type": true, - "issued_at": true, - "expires_at": true, - "nonce": true, - "declared_capabilities": { - "type": "array", - "description": "Capabilities the agent declares it has.", - "items": { - "type": "string" - }, - "minItems": 1 - } - }, - "required": [ - "type", - "declared_capabilities" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "allowlist" - } - } - }, - "then": { - "properties": { - "type": true, - "issued_at": true, - "expires_at": true, - "nonce": true, - "did": { - "type": "string", - "description": "The DID claiming to be on the allowlist." - } - }, - "required": [ - "type", - "did" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "reciprocal" - } - } - }, - "then": { - "properties": { - "type": true, - "issued_at": true, - "expires_at": true, - "nonce": true, - "entity_did": { - "type": "string", - "description": "The DID of the entity offering reciprocal access." - }, - "granted_access": { - "type": "string", - "description": "The access level being granted back.", - "examples": [ - "profile.*", - "*" - ] - } - }, - "required": [ - "type", - "entity_did", - "granted_access" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "proof_of_intent" - } - } - }, - "then": { - "properties": { - "type": true, - "issued_at": true, - "expires_at": true, - "nonce": true, - "intent_document": { - "type": "object", - "description": "Signed intent document from the human principal authorising the agent's action.", - "additionalProperties": true, - "required": [ - "intent_id", - "agent_did", - "principal_did", - "action", - "scope", - "principal_signature", - "created_at" - ], - "properties": { - "intent_id": { - "type": "string" - }, - "agent_did": { - "type": "string" - }, - "principal_did": { - "type": "string" - }, - "action": { - "type": "string" - }, - "scope": { - "type": "object", - "required": [ - "expires_at" - ], - "properties": { - "max_amount": { - "type": "number" - }, - "currency": { - "type": "string" - }, - "allowed_resources": { - "type": "array", - "items": { - "type": "string" - } - }, - "expires_at": { - "type": "string", - "format": "date-time" - } - } - }, - "principal_signature": { - "type": "string", - "minLength": 10 - }, - "created_at": { - "type": "string", - "format": "date-time" - } - } - } - }, - "required": [ - "type", - "intent_document" - ], - "additionalProperties": false - } - }, - { - "if": { - "properties": { - "type": { - "const": "data_request" - } - } - }, - "then": { - "properties": { - "type": true, - "verifiable_presentation": { - "type": "string", - "description": "W3C Verifiable Presentation (JWT or JSON-LD) containing the requested claims signed by the agent's DID key.", - "minLength": 10 - }, - "claimed_fields": { - "type": "array", - "description": "List of claim keys included in the VP (must match requested_claims).", - "items": { - "type": "string" - } - } - }, - "required": [ - "type", - "verifiable_presentation" - ], - "additionalProperties": false - } + "required": [ + "type" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "trust" + } + } + }, + "then": { + "properties": { + "type": true, + "issued_at": true, + "expires_at": true, + "nonce": true, + "self_attested": { + "type": "boolean", + "description": "If true, the subscriber claims their trust score meets the requirement. The publisher MUST verify this independently.", + "const": true + } + }, + "required": [ + "type", + "self_attested" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "identity" + } + } + }, + "then": { + "properties": { + "type": true, + "issued_at": true, + "expires_at": true, + "nonce": true, + "method": { + "type": "string", + "description": "The verification method used.", + "enum": [ + "did_verified", + "email_verified", + "domain_verified", + "kyc", + "any" + ] + }, + "evidence": { + "type": "string", + "description": "Verification evidence (e.g., a signed DID assertion, email verification token). Opaque to the protocol.", + "maxLength": 8192 + } + }, + "required": [ + "type", + "method" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "connection" + } + } + }, + "then": { + "properties": { + "type": true, + "issued_at": true, + "expires_at": true, + "nonce": true, + "subscriber_did": { + "type": "string", + "description": "The DID of the subscriber claiming the connection." + }, + "relation": { + "type": "string", + "description": "The claimed connection type.", + "enum": [ + "follower", + "following", + "mutual", + "any" + ] + } + }, + "required": [ + "type", + "subscriber_did" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "credential" + } + } + }, + "then": { + "properties": { + "type": true, + "issued_at": true, + "expires_at": true, + "nonce": true, + "credential": { + "type": "string", + "description": "The Verifiable Credential (encoded per the format field).", + "maxLength": 65536 + }, + "format": { + "type": "string", + "description": "Credential encoding format.", + "enum": [ + "jwt_vc", + "ldp_vc", + "sd_jwt_vc" + ], + "default": "jwt_vc" + } + }, + "required": [ + "type", + "credential", + "format" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "capability" + } + } + }, + "then": { + "properties": { + "type": true, + "issued_at": true, + "expires_at": true, + "nonce": true, + "declared_capabilities": { + "type": "array", + "description": "Capabilities the agent declares it has.", + "items": { + "type": "string" }, - { - "if": { - "properties": { - "type": { - "const": "agreement" - } + "minItems": 1 + } + }, + "required": [ + "type", + "declared_capabilities" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "allowlist" + } + } + }, + "then": { + "properties": { + "type": true, + "issued_at": true, + "expires_at": true, + "nonce": true, + "did": { + "type": "string", + "description": "The DID claiming to be on the allowlist." + } + }, + "required": [ + "type", + "did" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "reciprocal" + } + } + }, + "then": { + "properties": { + "type": true, + "issued_at": true, + "expires_at": true, + "nonce": true, + "entity_did": { + "type": "string", + "description": "The DID of the entity offering reciprocal access." + }, + "granted_access": { + "type": "string", + "description": "The access level being granted back.", + "examples": [ + "profile.*", + "*" + ] + } + }, + "required": [ + "type", + "entity_did", + "granted_access" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "proof_of_intent" + } + } + }, + "then": { + "properties": { + "type": true, + "issued_at": true, + "expires_at": true, + "nonce": true, + "intent_document": { + "type": "object", + "description": "Signed intent document from the human principal authorising the agent's action.", + "additionalProperties": true, + "required": [ + "intent_id", + "agent_did", + "principal_did", + "action", + "scope", + "principal_signature", + "created_at" + ], + "properties": { + "intent_id": { + "type": "string" + }, + "agent_did": { + "type": "string" + }, + "principal_did": { + "type": "string" + }, + "action": { + "type": "string" + }, + "scope": { + "type": "object", + "required": [ + "expires_at" + ], + "properties": { + "max_amount": { + "type": "number" + }, + "currency": { + "type": "string" + }, + "allowed_resources": { + "type": "array", + "items": { + "type": "string" } - }, - "then": { - "properties": { - "type": true, - "document_hash": { - "type": "string", - "description": "SHA-256 hash of the signed agreement document. Must match the hash in the gate requirement.", - "pattern": "^sha256:[a-f0-9]{64}$" - }, - "signature": { - "type": "string", - "description": "EdDSA or ES256K signature over the document_hash using the agent's DID private key (base64url or hex).", - "minLength": 10 - }, - "signer_did": { - "type": "string", - "description": "DID of the signing agent.", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "signature_algo": { - "type": "string", - "enum": [ - "EdDSA", - "ES256K" - ], - "default": "EdDSA" - } - }, - "required": [ - "type", - "document_hash", - "signature", - "signer_did" - ], - "additionalProperties": false + }, + "expires_at": { + "type": "string", + "format": "date-time" + } } + }, + "principal_signature": { + "type": "string", + "minLength": 10 + }, + "created_at": { + "type": "string", + "format": "date-time" + } + } + } + }, + "required": [ + "type", + "intent_document" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "data_request" + } + } + }, + "then": { + "properties": { + "type": true, + "verifiable_presentation": { + "type": "string", + "description": "W3C Verifiable Presentation (JWT or JSON-LD) containing the requested claims signed by the agent's DID key.", + "minLength": 10 + }, + "claimed_fields": { + "type": "array", + "description": "List of claim keys included in the VP (must match requested_claims).", + "items": { + "type": "string" } - ] + } + }, + "required": [ + "type", + "verifiable_presentation" + ], + "additionalProperties": false + } + }, + { + "if": { + "properties": { + "type": { + "const": "agreement" + } + } + }, + "then": { + "properties": { + "type": true, + "document_hash": { + "type": "string", + "description": "SHA-256 hash of the signed agreement document. Must match the hash in the gate requirement.", + "pattern": "^sha256:[a-f0-9]{64}$" + }, + "signature": { + "type": "string", + "description": "EdDSA or ES256K signature over the document_hash using the agent's DID private key (base64url or hex).", + "minLength": 10 + }, + "signer_did": { + "type": "string", + "description": "DID of the signing agent.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "signature_algo": { + "type": "string", + "enum": [ + "EdDSA", + "ES256K" + ], + "default": "EdDSA" + } + }, + "required": [ + "type", + "document_hash", + "signature", + "signer_did" + ], + "additionalProperties": false + } } + ] } -} \ No newline at end of file + } +} diff --git a/schemas/v0.1/operator.privacy-policy.json b/schemas/v0.1/operator.privacy-policy.json index e8a6a05..7aa7699 100644 --- a/schemas/v0.1/operator.privacy-policy.json +++ b/schemas/v0.1/operator.privacy-policy.json @@ -1,107 +1,107 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/operator.privacy-policy.json", - "title": "EEP Operator Privacy Policy Profile", - "description": "Signed JSON document that defines an agent's standing data-sharing policy. The agent consults this profile before responding to any data_request gate, enabling autonomous privacy decisions within human-defined constraints. (§7.4, Whitepaper).", - "type": "object", - "required": [ - "operator_did", - "version", - "issued_at" - ], - "additionalProperties": false, - "properties": { - "operator_did": { - "type": "string", - "description": "DID of the human/organizational operator that authored this policy.", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "version": { - "type": "string", - "description": "Monotonically increasing version identifier for this policy.", - "examples": [ - "1", - "2", - "2026-03-01" - ] - }, - "issued_at": { - "type": "string", - "description": "ISO 8601 datetime when this policy was issued/signed.", - "format": "date-time" - }, - "freely_shareable_claims": { - "type": "array", - "description": "Claim types the agent may share without any human confirmation.", - "items": { - "type": "string" - }, - "examples": [ - [ - "org_type", - "industry_sector", - "use_case_category" - ] - ] - }, - "human_confirmation_required": { - "type": "array", - "description": "Claim types that require explicit human confirmation before sharing. Agent pauses and surfaces the decision.", - "items": { - "type": "string" - }, - "examples": [ - [ - "owner_email", - "owner_name", - "billing_address" - ] - ] - }, - "unconditionally_refused": { - "type": "array", - "description": "Claim types that must never be shared, regardless of what access they would unlock.", - "items": { - "type": "string" - }, - "examples": [ - [ - "passport_number", - "medical_records", - "private_keys" - ] - ] - }, - "max_retention_days": { - "type": "integer", - "description": "Maximum retention_days the operator will accept in a data_request gate. Requests with higher retention must be refused or confirmed.", - "minimum": 0, - "maximum": 3650, - "default": 90 - }, - "allow_unverified_publishers": { - "type": "boolean", - "description": "Whether the agent may share data with publishers not registered on eep.dev. Set to false for strict privacy.", - "default": false - }, - "dpv_purposes_allowed": { - "type": "array", - "description": "W3C DPV purpose URIs the agent may share data for. Any purpose not in this list requires human confirmation.", - "items": { - "type": "string", - "pattern": "^dpv:[A-Z][a-zA-Z]+$" - }, - "examples": [ - [ - "dpv:ResearchAndDevelopment", - "dpv:ServiceProvision" - ] - ] - }, - "operator_signature": { - "type": "string", - "description": "EdDSA signature by operator_did over a canonical JSON serialization of this document (excluding operator_signature). Makes the policy tamper-evident.", - "minLength": 16 - } + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/operator.privacy-policy.json", + "title": "EEP Operator Privacy Policy Profile", + "description": "Signed JSON document that defines an agent's standing data-sharing policy. The agent consults this profile before responding to any data_request gate, enabling autonomous privacy decisions within human-defined constraints. (\u00a77.4, Whitepaper).", + "type": "object", + "required": [ + "operator_did", + "version", + "issued_at" + ], + "additionalProperties": false, + "properties": { + "operator_did": { + "type": "string", + "description": "DID of the human/organizational operator that authored this policy.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "version": { + "type": "string", + "description": "Monotonically increasing version identifier for this policy.", + "examples": [ + "1", + "2", + "2026-03-01" + ] + }, + "issued_at": { + "type": "string", + "description": "ISO 8601 datetime when this policy was issued/signed.", + "format": "date-time" + }, + "freely_shareable_claims": { + "type": "array", + "description": "Claim types the agent may share without any human confirmation.", + "items": { + "type": "string" + }, + "examples": [ + [ + "org_type", + "industry_sector", + "use_case_category" + ] + ] + }, + "human_confirmation_required": { + "type": "array", + "description": "Claim types that require explicit human confirmation before sharing. Agent pauses and surfaces the decision.", + "items": { + "type": "string" + }, + "examples": [ + [ + "owner_email", + "owner_name", + "billing_address" + ] + ] + }, + "unconditionally_refused": { + "type": "array", + "description": "Claim types that must never be shared, regardless of what access they would unlock.", + "items": { + "type": "string" + }, + "examples": [ + [ + "passport_number", + "medical_records", + "private_keys" + ] + ] + }, + "max_retention_days": { + "type": "integer", + "description": "Maximum retention_days the operator will accept in a data_request gate. Requests with higher retention must be refused or confirmed.", + "minimum": 0, + "maximum": 3650, + "default": 90 + }, + "allow_unverified_publishers": { + "type": "boolean", + "description": "Whether the agent may share data with publishers not registered on eep.dev. Set to false for strict privacy.", + "default": false + }, + "dpv_purposes_allowed": { + "type": "array", + "description": "W3C DPV purpose URIs the agent may share data for. Any purpose not in this list requires human confirmation.", + "items": { + "type": "string", + "pattern": "^dpv:[A-Z][a-zA-Z]+$" + }, + "examples": [ + [ + "dpv:ResearchAndDevelopment", + "dpv:ServiceProvision" + ] + ] + }, + "operator_signature": { + "type": "string", + "description": "EdDSA signature by operator_did over a canonical JSON serialization of this document (excluding operator_signature). Makes the policy tamper-evident.", + "minLength": 16 } -} \ No newline at end of file + } +} diff --git a/schemas/v0.1/operator.spending-policy.json b/schemas/v0.1/operator.spending-policy.json index f84aa02..0aed8da 100644 --- a/schemas/v0.1/operator.spending-policy.json +++ b/schemas/v0.1/operator.spending-policy.json @@ -1,115 +1,115 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/operator.spending-policy.json", - "title": "EEP Operator Spending Policy Profile", - "description": "Signed document defining an agent's spending constraints. Consulted before any payment gate interaction to ensure the agent acts within operator-defined financial limits. (§8.4, Whitepaper).", - "type": "object", - "required": [ - "operator_did", - "version", - "issued_at" - ], - "additionalProperties": false, - "properties": { - "operator_did": { - "type": "string", - "description": "DID of the human/organizational operator that authored this spending policy.", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "version": { - "type": "string", - "description": "Monotonically increasing version identifier.", - "examples": [ - "1", - "2" - ] - }, - "issued_at": { - "type": "string", - "description": "ISO 8601 datetime when this policy was issued.", - "format": "date-time" - }, - "max_per_transaction": { - "type": "object", - "description": "Maximum allowed spend per single transaction by currency.", - "additionalProperties": { - "type": "number", - "minimum": 0 - }, - "examples": [ - { - "usd": 10.00, - "eth": 0.005 - } - ] - }, - "max_per_hour": { - "type": "object", - "description": "Maximum cumulative spend per rolling 1-hour window by currency. Agent pauses if exceeded.", - "additionalProperties": { - "type": "number", - "minimum": 0 - }, - "examples": [ - { - "usd": 100.00 - } - ] - }, - "max_per_day": { - "type": "object", - "description": "Maximum cumulative spend per rolling 24-hour window by currency.", - "additionalProperties": { - "type": "number", - "minimum": 0 - } - }, - "approved_chains": { - "type": "array", - "description": "Blockchain networks the agent is permitted to transact on. Transactions on non-listed chains are refused.", - "items": { - "type": "string" - }, - "examples": [ - [ - "base", - "solana", - "ethereum" - ] - ] - }, - "approved_recipient_categories": { - "type": "array", - "description": "Gate recipient categories the agent may pay. If set, any recipient not matching is refused without human confirmation.", - "items": { - "type": "string" - }, - "examples": [ - [ - "Full", - "Standard", - "eep.dev-verified" - ] - ] - }, - "require_recipient_conformance_level": { - "type": "string", - "description": "Minimum EEP conformance level the recipient must hold before the agent may pay. Per Whitepaper §10.2: Core, Standard, or Full. The agent refuses payment to recipients below this tier without human confirmation.", - "enum": [ - "Core", - "Standard", - "Full" - ] - }, - "require_on_chain_confirmation": { - "type": "boolean", - "description": "If true, agent must wait for on-chain finality (using publisher's declared min_confirmations) before marking payment complete.", - "default": true - }, - "operator_signature": { - "type": "string", - "description": "EdDSA signature by operator_did over canonical JSON of this document (excluding operator_signature).", - "minLength": 16 + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/operator.spending-policy.json", + "title": "EEP Operator Spending Policy Profile", + "description": "Signed document defining an agent's spending constraints. Consulted before any payment gate interaction to ensure the agent acts within operator-defined financial limits. (\u00a78.4, Whitepaper).", + "type": "object", + "required": [ + "operator_did", + "version", + "issued_at" + ], + "additionalProperties": false, + "properties": { + "operator_did": { + "type": "string", + "description": "DID of the human/organizational operator that authored this spending policy.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "version": { + "type": "string", + "description": "Monotonically increasing version identifier.", + "examples": [ + "1", + "2" + ] + }, + "issued_at": { + "type": "string", + "description": "ISO 8601 datetime when this policy was issued.", + "format": "date-time" + }, + "max_per_transaction": { + "type": "object", + "description": "Maximum allowed spend per single transaction by currency.", + "additionalProperties": { + "type": "number", + "minimum": 0 + }, + "examples": [ + { + "usd": 10.0, + "eth": 0.005 } + ] + }, + "max_per_hour": { + "type": "object", + "description": "Maximum cumulative spend per rolling 1-hour window by currency. Agent pauses if exceeded.", + "additionalProperties": { + "type": "number", + "minimum": 0 + }, + "examples": [ + { + "usd": 100.0 + } + ] + }, + "max_per_day": { + "type": "object", + "description": "Maximum cumulative spend per rolling 24-hour window by currency.", + "additionalProperties": { + "type": "number", + "minimum": 0 + } + }, + "approved_chains": { + "type": "array", + "description": "Blockchain networks the agent is permitted to transact on. Transactions on non-listed chains are refused.", + "items": { + "type": "string" + }, + "examples": [ + [ + "base", + "solana", + "ethereum" + ] + ] + }, + "approved_recipient_categories": { + "type": "array", + "description": "Gate recipient categories the agent may pay. If set, any recipient not matching is refused without human confirmation.", + "items": { + "type": "string" + }, + "examples": [ + [ + "Full", + "Standard", + "eep.dev-verified" + ] + ] + }, + "require_recipient_conformance_level": { + "type": "string", + "description": "Minimum EEP conformance level the recipient must hold before the agent may pay. Per Whitepaper \u00a710.2: Core, Standard, or Full. The agent refuses payment to recipients below this tier without human confirmation.", + "enum": [ + "Core", + "Standard", + "Full" + ] + }, + "require_on_chain_confirmation": { + "type": "boolean", + "description": "If true, agent must wait for on-chain finality (using publisher's declared min_confirmations) before marking payment complete.", + "default": true + }, + "operator_signature": { + "type": "string", + "description": "EdDSA signature by operator_did over canonical JSON of this document (excluding operator_signature).", + "minLength": 16 } -} \ No newline at end of file + } +} diff --git a/schemas/v0.1/registry.search-result.json b/schemas/v0.1/registry.search-result.json index 90cb152..149cfc4 100644 --- a/schemas/v0.1/registry.search-result.json +++ b/schemas/v0.1/registry.search-result.json @@ -1,264 +1,264 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/registry.search-result.json", - "title": "EEP Registry Search Result", - "description": "Response schema for the eep.dev Registry Discovery API: GET /registry and GET /discover. Agents query the registry to find EEP publishers by category, gate type, conformance tier, or capability. The registry resolves queries across its own index and any federated peer registries. Implements Whitepaper §4.2 (eep.dev: The Protocol Registry and Bootstrapping Hub).", - "type": "object", - "required": [ - "results", - "total", - "page", - "per_page" - ], - "additionalProperties": false, - "properties": { - "results": { - "type": "array", - "description": "List of matching EEP publisher entries.", - "items": { - "$ref": "#/definitions/RegistryEntry" - } + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/registry.search-result.json", + "title": "EEP Registry Search Result", + "description": "Response schema for the eep.dev Registry Discovery API: GET /registry and GET /discover. Agents query the registry to find EEP publishers by category, gate type, conformance tier, or capability. The registry resolves queries across its own index and any federated peer registries. Implements Whitepaper \u00a74.2 (eep.dev: The Protocol Registry and Bootstrapping Hub).", + "type": "object", + "required": [ + "results", + "total", + "page", + "per_page" + ], + "additionalProperties": false, + "properties": { + "results": { + "type": "array", + "description": "List of matching EEP publisher entries.", + "items": { + "$ref": "#/$defs/RegistryEntry" + } + }, + "total": { + "type": "integer", + "description": "Total number of entities matching the query.", + "minimum": 0 + }, + "page": { + "type": "integer", + "description": "Current page number (1-indexed).", + "minimum": 1 + }, + "per_page": { + "type": "integer", + "description": "Number of results per page.", + "minimum": 1, + "maximum": 100, + "default": 20 + }, + "next_cursor": { + "type": "string", + "description": "Opaque cursor for fetching the next page. Absent when on the last page." + }, + "query_id": { + "type": "string", + "description": "Unique identifier for this paginated query session. Pass as ?query_id=... to retrieve subsequent pages." + }, + "resolved_from": { + "type": "array", + "description": "List of registry DIDs that contributed results (eep.dev + any federated registries consulted).", + "items": { + "type": "string", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "examples": [ + [ + "did:web:eep.dev", + "did:web:eep.eu" + ] + ] + } + }, + "$defs": { + "RegistryEntry": { + "$id": "#RegistryEntry", + "title": "Registry Entry", + "description": "A single EEP publisher entry returned from the registry search.", + "type": "object", + "required": [ + "did", + "manifest_url", + "conformance_tier", + "trust_score", + "registered_at" + ], + "additionalProperties": false, + "properties": { + "did": { + "type": "string", + "description": "W3C DID of the EEP publisher.", + "pattern": "^did:[a-z0-9]+:.+$", + "examples": [ + "did:web:api.example.com" + ] + }, + "name": { + "type": "string", + "description": "Human-readable display name of the entity.", + "maxLength": 256 }, - "total": { - "type": "integer", - "description": "Total number of entities matching the query.", - "minimum": 0 + "manifest_url": { + "type": "string", + "description": "URL of the entity's /.well-known/eep.json manifest.", + "format": "uri", + "examples": [ + "https://api.example.com/.well-known/eep.json" + ] }, - "page": { - "type": "integer", - "description": "Current page number (1-indexed).", - "minimum": 1 + "conformance_tier": { + "type": "string", + "description": "The EEP conformance tier the publisher holds (per their EEPConformanceCredential). Agents can filter by this field.", + "enum": [ + "Core", + "Standard", + "Full", + "unverified" + ], + "examples": [ + "Full" + ] }, - "per_page": { - "type": "integer", - "description": "Number of results per page.", - "minimum": 1, - "maximum": 100, - "default": 20 + "trust_score": { + "type": "number", + "description": "Registry-assigned trust score from 0.0 to 1.0. Computed from conformance credential freshness, DID document age, signed exchange history, and reputation signals. Agents can filter discovery queries by minimum trust score threshold.", + "minimum": 0.0, + "maximum": 1.0, + "examples": [ + 0.92, + 0.75 + ] }, - "next_cursor": { + "categories": { + "type": "array", + "description": "Semantic category tags declared by the publisher. Used for filtered discovery queries (e.g., ?category=supply-chain).", + "items": { + "type": "string" + }, + "examples": [ + [ + "financial-feeds", + "market-data" + ], + [ + "supply-chain", + "logistics" + ] + ] + }, + "gate_types": { + "type": "array", + "description": "Gate requirement types supported by this publisher. Agents filter by gate type when selecting interaction partners (e.g., ?gate=payment).", + "items": { "type": "string", - "description": "Opaque cursor for fetching the next page. Absent when on the last page." + "enum": [ + "credential", + "identity", + "agreement", + "data_request", + "payment", + "combined", + "proof_of_intent", + "public" + ] + } }, - "query_id": { + "layers": { + "type": "array", + "description": "Protocol layers supported. Agents filter by layer capability (e.g., ?supports=sse).", + "items": { "type": "string", - "description": "Unique identifier for this paginated query session. Pass as ?query_id=... to retrieve subsequent pages." + "enum": [ + "layer1", + "sse", + "webhook", + "websocket" + ] + }, + "examples": [ + [ + "layer1", + "sse", + "webhook", + "websocket" + ] + ] }, - "resolved_from": { - "type": "array", - "description": "List of registry DIDs that contributed results (eep.dev + any federated registries consulted).", - "items": { - "type": "string", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "examples": [ - [ - "did:web:eep.dev", - "did:web:eep.eu" - ] + "content_types": { + "type": "array", + "description": "MIME types the publisher can return.", + "items": { + "type": "string" + }, + "examples": [ + [ + "application/json", + "text/markdown", + "text/toon" ] + ] + }, + "registered_at": { + "type": "string", + "description": "ISO 8601 UTC timestamp when the entity registered with this registry.", + "format": "date-time" + }, + "conformance_credential_expires_at": { + "type": "string", + "description": "ISO 8601 UTC timestamp when the publisher's EEP Conformance Credential expires. Absent if unverified.", + "format": "date-time" + }, + "sector_extensions": { + "type": "array", + "description": "Sector-specific conformance extensions the publisher has passed (e.g., EEP-FinServ-1.0).", + "items": { + "type": "string", + "pattern": "^EEP-[A-Za-z]+(-[A-Za-z]+)?-\\d+\\.\\d+$" + } + }, + "data_residency": { + "type": "string", + "description": "Data residency constraint declared by the publisher (e.g., EU-only, US, Worldwide). Agents in regulated environments can filter by this field.", + "examples": [ + "EU-only", + "Worldwide" + ] + }, + "registry_source": { + "type": "string", + "description": "DID of the registry that indexed this entry. For federated results, this may differ from eep.dev.", + "pattern": "^did:[a-z0-9]+:.+$" } - }, - "definitions": { - "RegistryEntry": { - "$id": "#RegistryEntry", - "title": "Registry Entry", - "description": "A single EEP publisher entry returned from the registry search.", - "type": "object", - "required": [ - "did", - "manifest_url", - "conformance_tier", - "trust_score", - "registered_at" - ], - "additionalProperties": false, - "properties": { - "did": { - "type": "string", - "description": "W3C DID of the EEP publisher.", - "pattern": "^did:[a-z0-9]+:.+$", - "examples": [ - "did:web:api.example.com" - ] - }, - "name": { - "type": "string", - "description": "Human-readable display name of the entity.", - "maxLength": 256 - }, - "manifest_url": { - "type": "string", - "description": "URL of the entity's /.well-known/eep.json manifest.", - "format": "uri", - "examples": [ - "https://api.example.com/.well-known/eep.json" - ] - }, - "conformance_tier": { - "type": "string", - "description": "The EEP conformance tier the publisher holds (per their EEPConformanceCredential). Agents can filter by this field.", - "enum": [ - "Core", - "Standard", - "Full", - "unverified" - ], - "examples": [ - "Full" - ] - }, - "trust_score": { - "type": "number", - "description": "Registry-assigned trust score from 0.0 to 1.0. Computed from conformance credential freshness, DID document age, signed exchange history, and reputation signals. Agents can filter discovery queries by minimum trust score threshold.", - "minimum": 0.0, - "maximum": 1.0, - "examples": [ - 0.92, - 0.75 - ] - }, - "categories": { - "type": "array", - "description": "Semantic category tags declared by the publisher. Used for filtered discovery queries (e.g., ?category=supply-chain).", - "items": { - "type": "string" - }, - "examples": [ - [ - "financial-feeds", - "market-data" - ], - [ - "supply-chain", - "logistics" - ] - ] - }, - "gate_types": { - "type": "array", - "description": "Gate requirement types supported by this publisher. Agents filter by gate type when selecting interaction partners (e.g., ?gate=payment).", - "items": { - "type": "string", - "enum": [ - "credential", - "identity", - "agreement", - "data_request", - "payment", - "combined", - "proof_of_intent", - "public" - ] - } - }, - "layers": { - "type": "array", - "description": "Protocol layers supported. Agents filter by layer capability (e.g., ?supports=sse).", - "items": { - "type": "string", - "enum": [ - "layer1", - "sse", - "webhook", - "websocket" - ] - }, - "examples": [ - [ - "layer1", - "sse", - "webhook", - "websocket" - ] - ] - }, - "content_types": { - "type": "array", - "description": "MIME types the publisher can return.", - "items": { - "type": "string" - }, - "examples": [ - [ - "application/json", - "text/markdown", - "text/toon" - ] - ] - }, - "registered_at": { - "type": "string", - "description": "ISO 8601 UTC timestamp when the entity registered with this registry.", - "format": "date-time" - }, - "conformance_credential_expires_at": { - "type": "string", - "description": "ISO 8601 UTC timestamp when the publisher's EEP Conformance Credential expires. Absent if unverified.", - "format": "date-time" - }, - "sector_extensions": { - "type": "array", - "description": "Sector-specific conformance extensions the publisher has passed (e.g., EEP-FinServ-1.0).", - "items": { - "type": "string", - "pattern": "^EEP-[A-Za-z]+(-[A-Za-z]+)?-\\d+\\.\\d+$" - } - }, - "data_residency": { - "type": "string", - "description": "Data residency constraint declared by the publisher (e.g., EU-only, US, Worldwide). Agents in regulated environments can filter by this field.", - "examples": [ - "EU-only", - "Worldwide" - ] - }, - "registry_source": { - "type": "string", - "description": "DID of the registry that indexed this entry. For federated results, this may differ from eep.dev.", - "pattern": "^did:[a-z0-9]+:.+$" - } - } - } - }, - "examples": [ + } + } + }, + "examples": [ + { + "results": [ { - "results": [ - { - "did": "did:web:api.findata.example", - "name": "FinData Market Intelligence", - "manifest_url": "https://api.findata.example/.well-known/eep.json", - "conformance_tier": "Full", - "trust_score": 0.97, - "categories": [ - "financial-feeds", - "market-data" - ], - "gate_types": [ - "credential", - "payment" - ], - "layers": [ - "layer1", - "sse", - "webhook" - ], - "content_types": [ - "application/json", - "text/markdown" - ], - "registered_at": "2026-01-10T09:00:00Z", - "conformance_credential_expires_at": "2027-01-10T09:00:00Z", - "data_residency": "EU-only", - "registry_source": "did:web:eep.dev" - } - ], - "total": 1, - "page": 1, - "per_page": 20, - "resolved_from": [ - "did:web:eep.dev" - ] + "did": "did:web:api.findata.example", + "name": "FinData Market Intelligence", + "manifest_url": "https://api.findata.example/.well-known/eep.json", + "conformance_tier": "Full", + "trust_score": 0.97, + "categories": [ + "financial-feeds", + "market-data" + ], + "gate_types": [ + "credential", + "payment" + ], + "layers": [ + "layer1", + "sse", + "webhook" + ], + "content_types": [ + "application/json", + "text/markdown" + ], + "registered_at": "2026-01-10T09:00:00Z", + "conformance_credential_expires_at": "2027-01-10T09:00:00Z", + "data_residency": "EU-only", + "registry_source": "did:web:eep.dev" } - ] -} \ No newline at end of file + ], + "total": 1, + "page": 1, + "per_page": 20, + "resolved_from": [ + "did:web:eep.dev" + ] + } + ] +} diff --git a/schemas/v0.1/service.listing.json b/schemas/v0.1/service.listing.json index 27c2954..cb29332 100644 --- a/schemas/v0.1/service.listing.json +++ b/schemas/v0.1/service.listing.json @@ -1,310 +1,310 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/service.listing.json", - "title": "EEP Service Listing", - "description": "Schema for an entity's service catalog. Entities publish machine-readable service listings that agents can discover, compare, and purchase. Service names, categories, pricing, and availability are fully entity-defined. The protocol defines the envelope; the content is up to the implementer.", - "type": "object", - "required": [ - "entity_did", - "services" - ], - "additionalProperties": false, - "properties": { - "entity_did": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/service.listing.json", + "title": "EEP Service Listing", + "description": "Schema for an entity's service catalog. Entities publish machine-readable service listings that agents can discover, compare, and purchase. Service names, categories, pricing, and availability are fully entity-defined. The protocol defines the envelope; the content is up to the implementer.", + "type": "object", + "required": [ + "entity_did", + "services" + ], + "additionalProperties": false, + "properties": { + "entity_did": { + "type": "string", + "description": "The DID of the entity offering these services.", + "examples": [ + "did:web:example.com:u:alice" + ] + }, + "services": { + "type": "array", + "description": "List of services offered by this entity.", + "maxItems": 100, + "items": { + "$ref": "#/$defs/service" + } + } + }, + "$defs": { + "service": { + "type": "object", + "required": [ + "id", + "name", + "category", + "pricing", + "delivery" + ], + "additionalProperties": false, + "properties": { + "id": { + "type": "string", + "description": "Unique service identifier within this entity.", + "pattern": "^svc_[a-zA-Z0-9_]{1,64}$", + "examples": [ + "svc_consultation_30", + "svc_premium_feed" + ] + }, + "name": { + "type": "string", + "description": "Human-readable service name (entity-defined).", + "minLength": 1, + "maxLength": 256 + }, + "description": { + "type": "string", + "description": "Detailed description of what the service provides.", + "maxLength": 4096 + }, + "category": { + "type": "string", + "description": "Service category. Standard categories are suggested but any string is accepted. Agents match on tags and text search, not just category enums.", + "minLength": 1, + "maxLength": 64, + "examples": [ + "consulting", + "data_feed", + "api_access", + "content", + "computation", + "training", + "verification", + "integration" + ] + }, + "tags": { + "type": "array", + "description": "Entity-defined tags for discovery. Used in search queries.", + "items": { "type": "string", - "description": "The DID of the entity offering these services.", - "examples": [ - "did:web:example.com:u:alice" + "maxLength": 64 + }, + "maxItems": 20, + "examples": [ + [ + "ai", + "strategy", + "consulting", + "30min" ] + ] }, - "services": { - "type": "array", - "description": "List of services offered by this entity.", - "maxItems": 100, - "items": { - "$ref": "#/definitions/service" + "pricing": { + "type": "object", + "description": "Pricing for this service. Uses the same pricing model schema as commerce negotiations.", + "required": [ + "model", + "currency" + ], + "properties": { + "model": { + "type": "string", + "pattern": "^(fixed|per_request|per_event|subscription|metered|tiered_volume|free|x-[a-z][a-z0-9_-]*)$" + }, + "amount": { + "type": "number", + "minimum": 0 + }, + "currency": { + "type": "string", + "pattern": "^[a-z]{3}$" + }, + "period": { + "type": "string", + "enum": [ + "hour", + "day", + "week", + "month", + "year" + ] + }, + "unit": { + "type": "string" + }, + "rate": { + "type": "number", + "minimum": 0 } - } - }, - "definitions": { - "service": { - "type": "object", - "required": [ - "id", - "name", - "category", - "pricing", - "delivery" - ], - "additionalProperties": false, - "properties": { - "id": { - "type": "string", - "description": "Unique service identifier within this entity.", - "pattern": "^svc_[a-zA-Z0-9_]{1,64}$", - "examples": [ - "svc_consultation_30", - "svc_premium_feed" - ] - }, - "name": { - "type": "string", - "description": "Human-readable service name (entity-defined).", - "minLength": 1, - "maxLength": 256 - }, - "description": { - "type": "string", - "description": "Detailed description of what the service provides.", - "maxLength": 4096 - }, - "category": { - "type": "string", - "description": "Service category. Standard categories are suggested but any string is accepted. Agents match on tags and text search, not just category enums.", - "minLength": 1, - "maxLength": 64, - "examples": [ - "consulting", - "data_feed", - "api_access", - "content", - "computation", - "training", - "verification", - "integration" - ] - }, - "tags": { - "type": "array", - "description": "Entity-defined tags for discovery. Used in search queries.", - "items": { - "type": "string", - "maxLength": 64 - }, - "maxItems": 20, - "examples": [ - [ - "ai", - "strategy", - "consulting", - "30min" - ] - ] - }, - "pricing": { - "type": "object", - "description": "Pricing for this service. Uses the same pricing model schema as commerce negotiations.", - "required": [ - "model", - "currency" - ], - "properties": { - "model": { - "type": "string", - "pattern": "^(fixed|per_request|per_event|subscription|metered|tiered_volume|free|x-[a-z][a-z0-9_-]*)$" - }, - "amount": { - "type": "number", - "minimum": 0 - }, - "currency": { - "type": "string", - "pattern": "^[a-z]{3}$" - }, - "period": { - "type": "string", - "enum": [ - "hour", - "day", - "week", - "month", - "year" - ] - }, - "unit": { - "type": "string" - }, - "rate": { - "type": "number", - "minimum": 0 - } - } - }, - "availability": { + } + }, + "availability": { + "type": "object", + "description": "When this service is available.", + "properties": { + "type": { + "type": "string", + "description": "Availability mode.", + "enum": [ + "always", + "schedule", + "on_demand", + "limited" + ] + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule-based availability.", + "examples": [ + "UTC", + "America/New_York", + "Europe/Istanbul" + ] + }, + "schedule": { + "type": "object", + "description": "Weekly schedule (for 'schedule' type). Keys are day abbreviations.", + "patternProperties": { + "^(mon|tue|wed|thu|fri|sat|sun)$": { + "type": "array", + "items": { "type": "object", - "description": "When this service is available.", "properties": { - "type": { - "type": "string", - "description": "Availability mode.", - "enum": [ - "always", - "schedule", - "on_demand", - "limited" - ] - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule-based availability.", - "examples": [ - "UTC", - "America/New_York", - "Europe/Istanbul" - ] - }, - "schedule": { - "type": "object", - "description": "Weekly schedule (for 'schedule' type). Keys are day abbreviations.", - "patternProperties": { - "^(mon|tue|wed|thu|fri|sat|sun)$": { - "type": "array", - "items": { - "type": "object", - "properties": { - "start": { - "type": "string", - "pattern": "^[0-2][0-9]:[0-5][0-9]$" - }, - "end": { - "type": "string", - "pattern": "^[0-2][0-9]:[0-5][0-9]$" - } - } - } - } - } - }, - "slots_remaining": { - "type": "integer", - "description": "Remaining slots for 'limited' type.", - "minimum": 0 - }, - "next_available": { - "type": "string", - "description": "Next available time (ISO 8601).", - "format": "date-time" - } + "start": { + "type": "string", + "pattern": "^[0-2][0-9]:[0-5][0-9]$" + }, + "end": { + "type": "string", + "pattern": "^[0-2][0-9]:[0-5][0-9]$" + } } - }, - "delivery": { - "type": "string", - "description": "How the service is delivered after purchase.", - "enum": [ - "realtime", - "async", - "scheduled", - "sse", - "webhook", - "download", - "a2a_task" - ] - }, - "gate_requirements": { - "type": "array", - "description": "Optional additional requirements beyond payment to access this service. Uses the same requirement types as gate configuration.", - "items": { - "type": "object", - "required": [ - "type" - ], - "properties": { - "type": { - "type": "string" - } - }, - "additionalProperties": true - }, - "maxItems": 5 - }, - "negotiable": { - "type": "boolean", - "description": "Whether the entity is open to price negotiation via commerce messages.", - "default": false - }, - "rating": { - "$ref": "#/definitions/rating" - }, - "status": { - "type": "string", - "description": "Listing status.", - "enum": [ - "active", - "paused", - "sold_out", - "coming_soon" - ], - "default": "active" - }, - "created_at": { - "type": "string", - "format": "date-time" - }, - "updated_at": { - "type": "string", - "format": "date-time" - }, - "metadata": { - "type": "object", - "description": "Entity-defined metadata.", - "additionalProperties": true, - "maxProperties": 20 + } } + } + }, + "slots_remaining": { + "type": "integer", + "description": "Remaining slots for 'limited' type.", + "minimum": 0 + }, + "next_available": { + "type": "string", + "description": "Next available time (ISO 8601).", + "format": "date-time" } + } }, - "rating": { - "type": "object", - "description": "Aggregated rating for this service.", - "properties": { - "score": { - "type": "number", - "description": "Average rating score (1.0 to 5.0).", - "minimum": 1.0, - "maximum": 5.0 - }, - "count": { - "type": "integer", - "description": "Total number of reviews.", - "minimum": 0 - } - } + "delivery": { + "type": "string", + "description": "How the service is delivered after purchase.", + "enum": [ + "realtime", + "async", + "scheduled", + "sse", + "webhook", + "download", + "a2a_task" + ] }, - "review": { + "gate_requirements": { + "type": "array", + "description": "Optional additional requirements beyond payment to access this service. Uses the same requirement types as gate configuration.", + "items": { "type": "object", - "description": "A single review submitted by a subscriber.", "required": [ - "reviewer_did", - "score" + "type" ], "properties": { - "id": { - "type": "string", - "description": "Unique review identifier." - }, - "reviewer_did": { - "type": "string", - "description": "DID of the reviewer." - }, - "score": { - "type": "integer", - "description": "Rating score (1-5).", - "minimum": 1, - "maximum": 5 - }, - "comment": { - "type": "string", - "description": "Optional review text.", - "maxLength": 2048 - }, - "service_id": { - "type": "string", - "description": "The service being reviewed." - }, - "created_at": { - "type": "string", - "format": "date-time" - } - } + "type": { + "type": "string" + } + }, + "additionalProperties": true + }, + "maxItems": 5 + }, + "negotiable": { + "type": "boolean", + "description": "Whether the entity is open to price negotiation via commerce messages.", + "default": false + }, + "rating": { + "$ref": "#/$defs/rating" + }, + "status": { + "type": "string", + "description": "Listing status.", + "enum": [ + "active", + "paused", + "sold_out", + "coming_soon" + ], + "default": "active" + }, + "created_at": { + "type": "string", + "format": "date-time" + }, + "updated_at": { + "type": "string", + "format": "date-time" + }, + "metadata": { + "type": "object", + "description": "Entity-defined metadata.", + "additionalProperties": true, + "maxProperties": 20 + } + } + }, + "rating": { + "type": "object", + "description": "Aggregated rating for this service.", + "properties": { + "score": { + "type": "number", + "description": "Average rating score (1.0 to 5.0).", + "minimum": 1.0, + "maximum": 5.0 + }, + "count": { + "type": "integer", + "description": "Total number of reviews.", + "minimum": 0 + } + } + }, + "review": { + "type": "object", + "description": "A single review submitted by a subscriber.", + "required": [ + "reviewer_did", + "score" + ], + "properties": { + "id": { + "type": "string", + "description": "Unique review identifier." + }, + "reviewer_did": { + "type": "string", + "description": "DID of the reviewer." + }, + "score": { + "type": "integer", + "description": "Rating score (1-5).", + "minimum": 1, + "maximum": 5 + }, + "comment": { + "type": "string", + "description": "Optional review text.", + "maxLength": 2048 + }, + "service_id": { + "type": "string", + "description": "The service being reviewed." + }, + "created_at": { + "type": "string", + "format": "date-time" } + } } -} \ No newline at end of file + } +} diff --git a/schemas/v0.1/session.token.json b/schemas/v0.1/session.token.json index c86329b..1ff958c 100644 --- a/schemas/v0.1/session.token.json +++ b/schemas/v0.1/session.token.json @@ -1,81 +1,81 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/session.token.json", - "title": "EEP Session Token", - "description": "Signed session token issued by a publisher after successful gate requirement satisfaction. Presented via Authorization: EEP-Session header on subsequent requests. (§6, Whitepaper).", - "type": "object", - "required": [ - "agent_did", - "issuer_did", - "tiers", - "iat", - "exp", - "signature" - ], - "additionalProperties": false, - "properties": { - "agent_did": { - "type": "string", - "description": "DID of the agent this session token is bound to. Must match the presenting agent's DID key.", - "pattern": "^did:[a-z0-9]+:.+$", - "examples": [ - "did:web:agent.acme.ai", - "did:key:z6Mk..." - ] - }, - "issuer_did": { - "type": "string", - "description": "DID of the publisher that issued this session token. Used for signature verification.", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "tiers": { - "type": "array", - "description": "Gate tiers the agent has been granted access to.", - "minItems": 1, - "items": { - "type": "string", - "pattern": "^[a-z][a-z0-9_]{0,31}$" - }, - "examples": [ - [ - "pro", - "api_v2" - ] - ] - }, - "iat": { - "type": "integer", - "description": "Issued-at time as UNIX timestamp (seconds).", - "minimum": 0 - }, - "exp": { - "type": "integer", - "description": "Expiry time as UNIX timestamp (seconds). Must be greater than iat.", - "minimum": 0 - }, - "refresh_threshold": { - "type": "integer", - "description": "UNIX timestamp before which the agent should proactively request renewal. Typically exp minus 10% of the session duration.", - "minimum": 0 - }, - "context_id": { - "type": "string", - "description": "Opaque identifier the agent can use to resume interrupted operations, such as replaying missed events from a specific SSE position.", - "maxLength": 256, - "examples": [ - "ctx_a1b2c3d4", - "stream:offset:12345" - ] - }, - "gate_version": { - "type": "string", - "description": "Version of the gate configuration at the time this token was issued. Allows the publisher to detect config changes on renewal.", - "maxLength": 64 - }, - "signature": { - "type": "string", - "description": "EdDSA signature (base64url) over a canonical JSON serialization of all fields except 'signature', keyed to issuer_did's verification key.", - "minLength": 16 - } + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/session.token.json", + "title": "EEP Session Token", + "description": "Signed session token issued by a publisher after successful gate requirement satisfaction. Presented via Authorization: EEP-Session header on subsequent requests. (\u00a76, Whitepaper).", + "type": "object", + "required": [ + "agent_did", + "issuer_did", + "tiers", + "iat", + "exp", + "signature" + ], + "additionalProperties": false, + "properties": { + "agent_did": { + "type": "string", + "description": "DID of the agent this session token is bound to. Must match the presenting agent's DID key.", + "pattern": "^did:[a-z0-9]+:.+$", + "examples": [ + "did:web:agent.acme.ai", + "did:key:z6Mk..." + ] + }, + "issuer_did": { + "type": "string", + "description": "DID of the publisher that issued this session token. Used for signature verification.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "tiers": { + "type": "array", + "description": "Gate tiers the agent has been granted access to.", + "minItems": 1, + "items": { + "type": "string", + "pattern": "^[a-z][a-z0-9_]{0,31}$" + }, + "examples": [ + [ + "pro", + "api_v2" + ] + ] + }, + "iat": { + "type": "integer", + "description": "Issued-at time as UNIX timestamp (seconds).", + "minimum": 0 + }, + "exp": { + "type": "integer", + "description": "Expiry time as UNIX timestamp (seconds). Must be greater than iat.", + "minimum": 0 + }, + "refresh_threshold": { + "type": "integer", + "description": "UNIX timestamp before which the agent should proactively request renewal. Typically exp minus 10% of the session duration.", + "minimum": 0 + }, + "context_id": { + "type": "string", + "description": "Opaque identifier the agent can use to resume interrupted operations, such as replaying missed events from a specific SSE position.", + "maxLength": 256, + "examples": [ + "ctx_a1b2c3d4", + "stream:offset:12345" + ] + }, + "gate_version": { + "type": "string", + "description": "Version of the gate configuration at the time this token was issued. Allows the publisher to detect config changes on renewal.", + "maxLength": 64 + }, + "signature": { + "type": "string", + "description": "EdDSA signature (base64url) over a canonical JSON serialization of all fields except 'signature', keyed to issuer_did's verification key.", + "minLength": 16 } -} \ No newline at end of file + } +} diff --git a/schemas/v0.1/subscription.request.json b/schemas/v0.1/subscription.request.json index 818c95c..325cbbe 100644 --- a/schemas/v0.1/subscription.request.json +++ b/schemas/v0.1/subscription.request.json @@ -1,5 +1,5 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", + "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://eep.dev/schemas/v0.1/subscription.request.json", "title": "EEP Subscription Request", "description": "Schema for creating a new EEP event subscription. Validates the POST body sent to /eep/subscribe.", diff --git a/schemas/v0.1/ws-message.json b/schemas/v0.1/ws-message.json index 5b74970..ea1f9e6 100644 --- a/schemas/v0.1/ws-message.json +++ b/schemas/v0.1/ws-message.json @@ -1,595 +1,595 @@ { - "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://eep.dev/schemas/v0.1/ws-message.json", - "title": "EEP WebSocket Message", - "description": "Schema for all messages sent over the EEP Network Pulse (WebSocket) layer. Both client-to-server and server-to-client messages MUST conform to this schema. See SPECIFICATION.md §6.", - "type": "object", - "required": [ - "v", - "type", - "action" - ], - "additionalProperties": true, - "properties": { - "v": { - "type": "integer", - "description": "Protocol version. Clients MUST disconnect if they receive a version they do not support.", - "const": 1 - }, - "type": { - "type": "string", - "description": "The message category.", - "enum": [ - "entity", - "a2a", - "system", - "chat", - "commerce" - ] - }, - "action": { - "type": "string", - "description": "The specific action within the message type.", - "minLength": 1, - "maxLength": 64, - "examples": [ - "replay", - "auth_expiring", - "auth_refresh", - "auth_refreshed", - "error", - "subscribe", - "unsubscribe", - "event", - "data_withdrawal", - "session_refresh", - "session_revoked", - "commerce.rfp.open", - "commerce.rfp.bid.submit", - "commerce.rfp.bid.received", - "commerce.rfp.closed", - "commerce.dispute.open", - "commerce.dispute.evidence", - "commerce.dispute.resolved" - ] + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://eep.dev/schemas/v0.1/ws-message.json", + "title": "EEP WebSocket Message", + "description": "Schema for all messages sent over the EEP Network Pulse (WebSocket) layer. Both client-to-server and server-to-client messages MUST conform to this schema. See SPECIFICATION.md \u00a76.", + "type": "object", + "required": [ + "v", + "type", + "action" + ], + "additionalProperties": true, + "properties": { + "v": { + "type": "integer", + "description": "Protocol version. Clients MUST disconnect if they receive a version they do not support.", + "const": 1 + }, + "type": { + "type": "string", + "description": "The message category.", + "enum": [ + "entity", + "a2a", + "system", + "chat", + "commerce" + ] + }, + "action": { + "type": "string", + "description": "The specific action within the message type.", + "minLength": 1, + "maxLength": 64, + "examples": [ + "replay", + "auth_expiring", + "auth_refresh", + "auth_refreshed", + "error", + "subscribe", + "unsubscribe", + "event", + "data_withdrawal", + "session_refresh", + "session_revoked", + "commerce.rfp.open", + "commerce.rfp.bid.submit", + "commerce.rfp.bid.received", + "commerce.rfp.closed", + "commerce.dispute.open", + "commerce.dispute.evidence", + "commerce.dispute.resolved" + ] + }, + "seq": { + "type": "integer", + "description": "Monotonically increasing sequence number per channel. Used for ordering and gap detection. See SPECIFICATION.md \u00a76.3.", + "minimum": 0 + }, + "data": { + "type": "object", + "description": "The message payload. Structure varies by type and action." + }, + "error": { + "type": "object", + "description": "Error details, present only in system.error messages.", + "properties": { + "code": { + "type": "string", + "description": "Machine-readable error code.", + "examples": [ + "invalid_message", + "auth_required", + "rate_limited" + ] }, - "seq": { - "type": "integer", - "description": "Monotonically increasing sequence number per channel. Used for ordering and gap detection. See SPECIFICATION.md §6.3.", - "minimum": 0 + "message": { + "type": "string", + "description": "Human-readable error description." + } + }, + "required": [ + "code", + "message" + ] + } + }, + "allOf": [ + { + "if": { + "properties": { + "type": { + "const": "system" + }, + "action": { + "const": "auth_expiring" + } }, - "data": { + "required": [ + "type", + "action" + ] + }, + "then": { + "properties": { + "data": { "type": "object", - "description": "The message payload. Structure varies by type and action." + "required": [ + "expires_in" + ], + "properties": { + "expires_in": { + "type": "integer", + "description": "Seconds until the current JWT expires.", + "minimum": 0 + } + } + } + } + } + }, + { + "if": { + "properties": { + "type": { + "const": "system" + }, + "action": { + "const": "auth_refresh" + } }, - "error": { + "required": [ + "type", + "action" + ] + }, + "then": { + "properties": { + "data": { "type": "object", - "description": "Error details, present only in system.error messages.", - "properties": { - "code": { - "type": "string", - "description": "Machine-readable error code.", - "examples": [ - "invalid_message", - "auth_required", - "rate_limited" - ] - }, - "message": { - "type": "string", - "description": "Human-readable error description." - } - }, "required": [ - "code", - "message" - ] + "token" + ], + "properties": { + "token": { + "type": "string", + "description": "The new JWT token.", + "minLength": 1 + } + } + } } + } }, - "allOf": [ - { - "if": { - "properties": { - "type": { - "const": "system" - }, - "action": { - "const": "auth_expiring" - } - }, - "required": [ - "type", - "action" - ] - }, - "then": { - "properties": { - "data": { - "type": "object", - "required": [ - "expires_in" - ], - "properties": { - "expires_in": { - "type": "integer", - "description": "Seconds until the current JWT expires.", - "minimum": 0 - } - } - } - } - } + { + "if": { + "properties": { + "type": { + "const": "system" + }, + "action": { + "const": "replay" + } }, - { - "if": { - "properties": { - "type": { - "const": "system" - }, - "action": { - "const": "auth_refresh" - } - }, - "required": [ - "type", - "action" - ] - }, - "then": { - "properties": { - "data": { - "type": "object", - "required": [ - "token" - ], - "properties": { - "token": { - "type": "string", - "description": "The new JWT token.", - "minLength": 1 - } - } - } - } + "required": [ + "type", + "action" + ] + }, + "then": { + "properties": { + "data": { + "type": "object", + "required": [ + "from_seq" + ], + "properties": { + "from_seq": { + "type": "integer", + "description": "Request replay of all messages from this sequence number.", + "minimum": 0 + } } + } + } + } + }, + { + "if": { + "properties": { + "action": { + "const": "data_withdrawal" + } }, - { - "if": { - "properties": { - "type": { - "const": "system" - }, - "action": { - "const": "replay" - } - }, - "required": [ - "type", - "action" - ] - }, - "then": { - "properties": { - "data": { - "type": "object", - "required": [ - "from_seq" - ], - "properties": { - "from_seq": { - "type": "integer", - "description": "Request replay of all messages from this sequence number.", - "minimum": 0 - } - } - } - } + "required": [ + "action" + ] + }, + "then": { + "description": "Agent requests withdrawal of previously shared claim data. Publisher must acknowledge within 24h (\u00a77.3 Right of Withdrawal, Whitepaper G17).", + "properties": { + "data": { + "type": "object", + "required": [ + "claim_id", + "agent_did", + "reason" + ], + "additionalProperties": true, + "properties": { + "claim_id": { + "type": "string", + "description": "Identifier of the claim to be withdrawn." + }, + "agent_did": { + "type": "string", + "description": "DID of the requesting agent. Must match the original data_request submitter.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "reason": { + "type": "string", + "description": "W3C DPV reason for withdrawal (e.g. dpv:WithdrawConsent) or human-readable string." + }, + "signed_request": { + "type": "string", + "description": "Optional EdDSA signature over claim_id+agent_did+reason to prove withdrawal intent." + } } + } + } + } + }, + { + "if": { + "properties": { + "action": { + "const": "session_revoked" + } }, - { - "if": { - "properties": { - "action": { - "const": "data_withdrawal" - } - }, - "required": [ - "action" + "required": [ + "action" + ] + }, + "then": { + "description": "Publisher revokes an agent's session in real time. The agent MUST stop using the session token immediately. See SPECIFICATION.md \u00a711.7 (G25).", + "properties": { + "data": { + "type": "object", + "required": [ + "session_id", + "agent_did", + "reason", + "revoked_at" + ], + "additionalProperties": true, + "properties": { + "session_id": { + "type": "string", + "description": "Identifier of the session token being revoked. Corresponds to the 'context_id' in the session token." + }, + "agent_did": { + "type": "string", + "description": "DID of the agent whose session is being revoked.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "publisher_did": { + "type": "string", + "description": "DID of the publisher issuing the revocation (for verification).", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "reason": { + "type": "string", + "description": "Machine-readable or human-readable reason for revocation.", + "examples": [ + "agreement_violation", + "payment_failed", + "operator_request", + "security_incident", + "session_expired" ] - }, - "then": { - "description": "Agent requests withdrawal of previously shared claim data. Publisher must acknowledge within 24h (§7.3 Right of Withdrawal, Whitepaper G17).", - "properties": { - "data": { - "type": "object", - "required": [ - "claim_id", - "agent_did", - "reason" - ], - "additionalProperties": true, - "properties": { - "claim_id": { - "type": "string", - "description": "Identifier of the claim to be withdrawn." - }, - "agent_did": { - "type": "string", - "description": "DID of the requesting agent. Must match the original data_request submitter.", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "reason": { - "type": "string", - "description": "W3C DPV reason for withdrawal (e.g. dpv:WithdrawConsent) or human-readable string." - }, - "signed_request": { - "type": "string", - "description": "Optional EdDSA signature over claim_id+agent_did+reason to prove withdrawal intent." - } - } - } - } + }, + "revoked_at": { + "type": "string", + "description": "ISO 8601 UTC timestamp of the revocation.", + "format": "date-time" + }, + "re_auth_required": { + "type": "boolean", + "description": "If true, the agent may re-authenticate by re-satisfying the gate requirements. If false, the agent is permanently blocked.", + "default": true + } } + } + } + } + }, + { + "if": { + "properties": { + "action": { + "const": "commerce.rfp.open" + } }, - { - "if": { - "properties": { - "action": { - "const": "session_revoked" - } - }, - "required": [ - "action" + "required": [ + "action" + ] + }, + "then": { + "description": "Publisher opens a Request-for-Proposals auction. Interested agents may submit bids before close_time. See SPECIFICATION.md \u00a76.5.3 (G28).", + "properties": { + "data": { + "type": "object", + "required": [ + "rfp_id", + "publisher_did", + "description", + "mechanism", + "close_time" + ], + "additionalProperties": true, + "properties": { + "rfp_id": { + "type": "string", + "description": "Unique identifier for this auction / RFP round." + }, + "publisher_did": { + "type": "string", + "description": "DID of the publisher opening the auction.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "description": { + "type": "string", + "description": "Human-readable description of the resource being auctioned." + }, + "mechanism": { + "type": "string", + "description": "Auction mechanism type.", + "enum": [ + "first_price", + "vickrey", + "reverse" ] - }, - "then": { - "description": "Publisher revokes an agent's session in real time. The agent MUST stop using the session token immediately. See SPECIFICATION.md §11.7 (G25).", - "properties": { - "data": { - "type": "object", - "required": [ - "session_id", - "agent_did", - "reason", - "revoked_at" - ], - "additionalProperties": true, - "properties": { - "session_id": { - "type": "string", - "description": "Identifier of the session token being revoked. Corresponds to the 'context_id' in the session token." - }, - "agent_did": { - "type": "string", - "description": "DID of the agent whose session is being revoked.", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "publisher_did": { - "type": "string", - "description": "DID of the publisher issuing the revocation (for verification).", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "reason": { - "type": "string", - "description": "Machine-readable or human-readable reason for revocation.", - "examples": [ - "agreement_violation", - "payment_failed", - "operator_request", - "security_incident", - "session_expired" - ] - }, - "revoked_at": { - "type": "string", - "description": "ISO 8601 UTC timestamp of the revocation.", - "format": "date-time" - }, - "re_auth_required": { - "type": "boolean", - "description": "If true, the agent may re-authenticate by re-satisfying the gate requirements. If false, the agent is permanently blocked.", - "default": true - } - } - } - } - } - }, - { - "if": { - "properties": { - "action": { - "const": "commerce.rfp.open" - } - }, - "required": [ - "action" + }, + "close_time": { + "type": "string", + "description": "ISO 8601 UTC timestamp when the auction closes. No bids accepted after this time.", + "format": "date-time" + }, + "reserve_price": { + "type": "number", + "description": "Minimum acceptable bid (in USD-equivalent). Bids below this are automatically rejected.", + "minimum": 0 + }, + "currency": { + "type": "string", + "description": "Currency for bid amounts.", + "default": "USD", + "examples": [ + "USD", + "USDC", + "SOL" ] - }, - "then": { - "description": "Publisher opens a Request-for-Proposals auction. Interested agents may submit bids before close_time. See SPECIFICATION.md §6.5.3 (G28).", - "properties": { - "data": { - "type": "object", - "required": [ - "rfp_id", - "publisher_did", - "description", - "mechanism", - "close_time" - ], - "additionalProperties": true, - "properties": { - "rfp_id": { - "type": "string", - "description": "Unique identifier for this auction / RFP round." - }, - "publisher_did": { - "type": "string", - "description": "DID of the publisher opening the auction.", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "description": { - "type": "string", - "description": "Human-readable description of the resource being auctioned." - }, - "mechanism": { - "type": "string", - "description": "Auction mechanism type.", - "enum": [ - "first_price", - "vickrey", - "reverse" - ] - }, - "close_time": { - "type": "string", - "description": "ISO 8601 UTC timestamp when the auction closes. No bids accepted after this time.", - "format": "date-time" - }, - "reserve_price": { - "type": "number", - "description": "Minimum acceptable bid (in USD-equivalent). Bids below this are automatically rejected.", - "minimum": 0 - }, - "currency": { - "type": "string", - "description": "Currency for bid amounts.", - "default": "USD", - "examples": [ - "USD", - "USDC", - "SOL" - ] - }, - "manifest_hash": { - "type": "string", - "description": "SHA-256 hash of the publisher manifest update that committed these auction parameters. Prevents last-minute manipulation.", - "pattern": "^sha256:[a-f0-9]{64}$" - } - } - } - } + }, + "manifest_hash": { + "type": "string", + "description": "SHA-256 hash of the publisher manifest update that committed these auction parameters. Prevents last-minute manipulation.", + "pattern": "^sha256:[a-f0-9]{64}$" + } } + } + } + } + }, + { + "if": { + "properties": { + "action": { + "const": "commerce.rfp.bid.submit" + } }, - { - "if": { - "properties": { - "action": { - "const": "commerce.rfp.bid.submit" - } - }, - "required": [ - "action" + "required": [ + "action" + ] + }, + "then": { + "description": "Agent submits a bid for an open RFP auction. Must be received before close_time. See SPECIFICATION.md \u00a76.5.3 (G28).", + "properties": { + "data": { + "type": "object", + "required": [ + "rfp_id", + "bidder_did", + "bid_amount", + "bid_currency", + "signed_bid" + ], + "additionalProperties": true, + "properties": { + "rfp_id": { + "type": "string", + "description": "ID of the RFP being bid on." + }, + "bidder_did": { + "type": "string", + "description": "DID of the bidding agent.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "bid_amount": { + "type": "number", + "description": "Bid amount in bid_currency.", + "exclusiveMinimum": 0 + }, + "bid_currency": { + "type": "string", + "description": "Currency of the bid.", + "examples": [ + "USD", + "USDC", + "SOL" ] - }, - "then": { - "description": "Agent submits a bid for an open RFP auction. Must be received before close_time. See SPECIFICATION.md §6.5.3 (G28).", - "properties": { - "data": { - "type": "object", - "required": [ - "rfp_id", - "bidder_did", - "bid_amount", - "bid_currency", - "signed_bid" - ], - "additionalProperties": true, - "properties": { - "rfp_id": { - "type": "string", - "description": "ID of the RFP being bid on." - }, - "bidder_did": { - "type": "string", - "description": "DID of the bidding agent.", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "bid_amount": { - "type": "number", - "description": "Bid amount in bid_currency.", - "exclusiveMinimum": 0 - }, - "bid_currency": { - "type": "string", - "description": "Currency of the bid.", - "examples": [ - "USD", - "USDC", - "SOL" - ] - }, - "signed_bid": { - "type": "string", - "description": "EdDSA signature over rfp_id+bidder_did+bid_amount+bid_currency by the bidder's DID key, preventing bid repudiation." - } - } - } - } + }, + "signed_bid": { + "type": "string", + "description": "EdDSA signature over rfp_id+bidder_did+bid_amount+bid_currency by the bidder's DID key, preventing bid repudiation." + } } + } + } + } + }, + { + "if": { + "properties": { + "action": { + "const": "commerce.rfp.closed" + } }, - { - "if": { - "properties": { - "action": { - "const": "commerce.rfp.closed" - } - }, - "required": [ - "action" - ] - }, - "then": { - "description": "Publisher closes the RFP auction and announces the winner. The winner receives an AllocationReceipt VC. See SPECIFICATION.md §6.5.3 (G28).", - "properties": { - "data": { - "type": "object", - "required": [ - "rfp_id", - "winner_did", - "winning_bid", - "closed_at", - "allocation_receipt_vc" - ], - "additionalProperties": true, - "properties": { - "rfp_id": { - "type": "string", - "description": "ID of the closed auction." - }, - "winner_did": { - "type": "string", - "description": "DID of the winning bidder.", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "winning_bid": { - "type": "number", - "description": "Winning bid amount.", - "exclusiveMinimum": 0 - }, - "total_bids": { - "type": "integer", - "description": "Total number of bids received (informational).", - "minimum": 1 - }, - "closed_at": { - "type": "string", - "description": "ISO 8601 UTC timestamp when the auction was closed.", - "format": "date-time" - }, - "allocation_receipt_vc": { - "type": "object", - "description": "W3C Verifiable Credential (EEPAllocationReceipt) issued to the winner. Contains the agreed terms and access entitlement duration." - } - } - } - } + "required": [ + "action" + ] + }, + "then": { + "description": "Publisher closes the RFP auction and announces the winner. The winner receives an AllocationReceipt VC. See SPECIFICATION.md \u00a76.5.3 (G28).", + "properties": { + "data": { + "type": "object", + "required": [ + "rfp_id", + "winner_did", + "winning_bid", + "closed_at", + "allocation_receipt_vc" + ], + "additionalProperties": true, + "properties": { + "rfp_id": { + "type": "string", + "description": "ID of the closed auction." + }, + "winner_did": { + "type": "string", + "description": "DID of the winning bidder.", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "winning_bid": { + "type": "number", + "description": "Winning bid amount.", + "exclusiveMinimum": 0 + }, + "total_bids": { + "type": "integer", + "description": "Total number of bids received (informational).", + "minimum": 1 + }, + "closed_at": { + "type": "string", + "description": "ISO 8601 UTC timestamp when the auction was closed.", + "format": "date-time" + }, + "allocation_receipt_vc": { + "type": "object", + "description": "W3C Verifiable Credential (EEPAllocationReceipt) issued to the winner. Contains the agreed terms and access entitlement duration." + } } + } + } + } + }, + { + "if": { + "properties": { + "type": { + "const": "commerce" + }, + "action": { + "const": "commerce.dispute.open" + } }, - { - "if": { - "properties": { - "type": { - "const": "commerce" - }, - "action": { - "const": "commerce.dispute.open" - } + "required": [ + "type", + "action" + ] + }, + "then": { + "description": "Subscriber opens a post-payment dispute (SPEC \u00a715.4.1).", + "properties": { + "data": { + "type": "object", + "required": [ + "negotiation_id", + "subscriber_did", + "reason_code" + ], + "additionalProperties": true, + "properties": { + "negotiation_id": { + "type": "string" + }, + "subscriber_did": { + "type": "string", + "pattern": "^did:[a-z0-9]+:.+$" + }, + "reason_code": { + "type": "string", + "description": "Machine-readable reason (e.g. sla_violation, stream_stopped)." + }, + "evidence": { + "type": "array", + "items": { + "type": "string" }, - "required": [ - "type", - "action" + "description": "URIs or content hashes supporting the dispute." + }, + "requested_remedy": { + "type": "string", + "enum": [ + "refund", + "service_resume", + "reputation_penalty" ] - }, - "then": { - "description": "Subscriber opens a post-payment dispute (SPEC §15.4.1).", - "properties": { - "data": { - "type": "object", - "required": [ - "negotiation_id", - "subscriber_did", - "reason_code" - ], - "additionalProperties": true, - "properties": { - "negotiation_id": { - "type": "string" - }, - "subscriber_did": { - "type": "string", - "pattern": "^did:[a-z0-9]+:.+$" - }, - "reason_code": { - "type": "string", - "description": "Machine-readable reason (e.g. sla_violation, stream_stopped)." - }, - "evidence": { - "type": "array", - "items": { - "type": "string" - }, - "description": "URIs or content hashes supporting the dispute." - }, - "requested_remedy": { - "type": "string", - "enum": [ - "refund", - "service_resume", - "reputation_penalty" - ] - } - } - } - } + } } + } + } + } + }, + { + "if": { + "properties": { + "type": { + "const": "commerce" + }, + "action": { + "const": "commerce.dispute.resolved" + } }, - { - "if": { - "properties": { - "type": { - "const": "commerce" - }, - "action": { - "const": "commerce.dispute.resolved" - } - }, - "required": [ - "type", - "action" + "required": [ + "type", + "action" + ] + }, + "then": { + "properties": { + "data": { + "type": "object", + "required": [ + "negotiation_id", + "outcome" + ], + "additionalProperties": true, + "properties": { + "negotiation_id": { + "type": "string" + }, + "outcome": { + "type": "string", + "enum": [ + "refunded", + "rejected", + "penalty_applied", + "dismissed" ] - }, - "then": { - "properties": { - "data": { - "type": "object", - "required": [ - "negotiation_id", - "outcome" - ], - "additionalProperties": true, - "properties": { - "negotiation_id": { - "type": "string" - }, - "outcome": { - "type": "string", - "enum": [ - "refunded", - "rejected", - "penalty_applied", - "dismissed" - ] - }, - "publisher_did": { - "type": "string", - "pattern": "^did:[a-z0-9]+:.+$" - } - } - } - } + }, + "publisher_did": { + "type": "string", + "pattern": "^did:[a-z0-9]+:.+$" + } } + } } - ] -} \ No newline at end of file + } + } + ] +} diff --git a/tests/bench.test.ts b/tests/bench.test.ts index e8a75ff..8513019 100644 --- a/tests/bench.test.ts +++ b/tests/bench.test.ts @@ -1,6 +1,8 @@ // Copyright 2026 EEP Contributors — Apache-2.0 import { describe, it, expect, beforeAll } from 'vitest'; -import Ajv, { type ValidateFunction } from 'ajv'; +// Schemas are JSON Schema 2020-12; Ajv's default export only +// understands draft-07, so the 2020-12 build is required. +import Ajv2020, { type ValidateFunction } from 'ajv/dist/2020.js'; import addFormats from 'ajv-formats'; import fs from 'node:fs'; import path from 'node:path'; @@ -18,7 +20,7 @@ describe('EEP Schema Validation Performance', () => { let pulseValidate: ValidateFunction; beforeAll(() => { - const ajv = new Ajv({ allErrors: true, strict: false }); + const ajv = new Ajv2020({ allErrors: true, strict: false }); addFormats(ajv); envelopeValidate = ajv.compile(loadSchema('event.envelope.json')); diff --git a/tests/conformance-fixtures.test.ts b/tests/conformance-fixtures.test.ts index 781d05d..d9406cb 100644 --- a/tests/conformance-fixtures.test.ts +++ b/tests/conformance-fixtures.test.ts @@ -19,7 +19,9 @@ import { readFileSync, readdirSync, statSync } from 'node:fs'; import { join, resolve, dirname } from 'node:path'; import { createHmac } from 'node:crypto'; import { fileURLToPath } from 'node:url'; -import Ajv from 'ajv'; +// Schemas are JSON Schema 2020-12; Ajv's default export only +// understands draft-07, so the 2020-12 build is required. +import Ajv2020 from 'ajv/dist/2020.js'; import addFormats from 'ajv-formats'; const __dirname = dirname(fileURLToPath(import.meta.url)); @@ -44,7 +46,7 @@ const manifest = JSON.parse( readFileSync(join(FIXTURES_DIR, 'manifest.json'), 'utf8') ) as { fixtures: ManifestEntry[]; spec_version: string }; -const ajv = new Ajv({ strict: false, allErrors: true }); +const ajv = new Ajv2020({ strict: false, allErrors: true }); addFormats(ajv); // Pre-load every schema referenced in the manifest. We add them to Ajv by diff --git a/tests/cross-impl/test_discovery_manifest.py b/tests/cross-impl/test_discovery_manifest.py index 463e3ad..7b27e7c 100644 --- a/tests/cross-impl/test_discovery_manifest.py +++ b/tests/cross-impl/test_discovery_manifest.py @@ -26,7 +26,7 @@ def test_schema_is_valid_json(self): """Schema must be valid JSON.""" with open(SCHEMA_PATH) as f: schema = json.load(f) - assert schema["$schema"] == "http://json-schema.org/draft-07/schema#" + assert schema["$schema"] == "https://json-schema.org/draft/2020-12/schema" assert "did" in schema.get("required", []) def test_schema_required_fields(self): diff --git a/tests/test_schemas.test.ts b/tests/test_schemas.test.ts index 81df2a4..ff512ab 100644 --- a/tests/test_schemas.test.ts +++ b/tests/test_schemas.test.ts @@ -1,6 +1,8 @@ // Copyright 2026 EEP Contributors — Apache-2.0 import { describe, it, expect, beforeAll } from 'vitest'; -import Ajv, { type ValidateFunction } from 'ajv'; +// Schemas are JSON Schema 2020-12; Ajv's default export only +// understands draft-07, so the 2020-12 build is required. +import Ajv2020, { type ValidateFunction } from 'ajv/dist/2020.js'; import addFormats from 'ajv-formats'; import fs from 'node:fs'; import path from 'node:path'; @@ -61,7 +63,7 @@ describe('EEP JSON Schema Validation', () => { let ajv: Ajv; beforeAll(() => { - ajv = new Ajv({ allErrors: true, strict: false }); + ajv = new Ajv2020({ allErrors: true, strict: false }); addFormats(ajv); }); @@ -812,7 +814,7 @@ describe('EEP JSON Schema Validation', () => { beforeAll(() => { const envelopeSchema = loadSchema('event.envelope.json'); const deliverySchema = loadSchema('delivery.payload.json'); - const localAjv = new Ajv({ allErrors: true, strict: false }); + const localAjv = new Ajv2020({ allErrors: true, strict: false }); addFormats(localAjv); localAjv.addSchema(envelopeSchema, './event.envelope.json'); validate = localAjv.compile(deliverySchema); @@ -890,11 +892,28 @@ describe('EEP JSON Schema Validation', () => { } }); - it('all schemas use draft-07', () => { + // OpenAPI 3.1's schema dialect IS JSON Schema 2020-12, and setup-cli + // emits `openapi: "3.1.0"` documents that $ref these files. While the + // schemas declared draft-07, those generated documents referenced + // draft-07 schemas from a 2020-12 context — a dialect mismatch that + // strict OpenAPI 3.1 tooling trips on. + it('all schemas use JSON Schema 2020-12', () => { const schemaFiles = fs.readdirSync(SCHEMAS_DIR).filter((f: string) => f.endsWith('.json')); for (const file of schemaFiles) { const schema = loadSchema(file) as Record; - expect(schema.$schema).toBe('http://json-schema.org/draft-07/schema#'); + expect(schema.$schema).toBe('https://json-schema.org/draft/2020-12/schema'); + } + }); + + // `definitions` was renamed to `$defs` in 2019-09. A file still using + // the old keyword would validate as an unknown annotation rather than + // failing loudly, so subschemas would silently stop being reachable. + it('uses $defs rather than the draft-07 definitions keyword', () => { + const schemaFiles = fs.readdirSync(SCHEMAS_DIR).filter((f: string) => f.endsWith('.json')); + for (const file of schemaFiles) { + const raw = fs.readFileSync(path.join(SCHEMAS_DIR, file), 'utf-8'); + expect(raw).not.toContain('"definitions"'); + expect(raw).not.toContain('#/definitions/'); } });