{
  "schema_version": "1.4",
  "name": "Azalee A2A Agent Enrollment",
  "provider": "Azalee",
  "url": "https://azalee.garden",
  "description": "Machine-first enrollment for AI agents that need tamper-evident audit logging. The agent starts the flow, proves control of its real HTTPS host, and then waits for the verified human owner to approve or reject the billable connection. No A2A dashboard setup page and no public-chat pairing are used.",
  "protocol": "azalee-a2a-enrollment-v1",
  "human_approval_required": true,
  "bot_admin_proof_required": true,
  "public_chat_enrollment_allowed": false,
  "ui_required_for_agent": false,
  "billing_acknowledgement_required": true,
  "discovery_urls": [
    "https://azalee.garden/.well-known/azalee-a2a.json",
    "https://azalee.garden/.well-known/a2a-agent-card.json",
    "https://azalee.garden/.well-known/agent-card.json",
    "https://azalee.garden/a2a",
    "https://azalee.garden/a2a.json"
  ],
  "product": {
    "name": "Azalee Proof",
    "pricing_model": "per_ai_system",
    "monthly_eur": 29,
    "annual_eur": 290,
    "trial": "30 days, one AI system, no payment method required",
    "included": "Webhook/API logging, Verify, evidence exports, daily external RFC 3161 anchoring and 24-month retention.",
    "timestamp_qualification": "A timestamp is labelled qualified eIDAS only when the exact timestamp service is verified in the EU Trusted List and explicitly enabled by the operator.",
    "legacy_requested_tier_policy": "requestedTier is accepted only for backward protocol compatibility and does not change price, features or storage. Every approved connection receives the complete Azalee Proof entitlement."
  },
  "security": {
    "agent_start": "The agent requests a short-lived signed agentStartToken for one exact owner email and one exact standard Agent Card URL.",
    "bot_admin_proof": "The agent publishes the returned challenge at /.well-known/azalee-agent-ownership.json on the same public HTTPS origin as its standard A2A Agent Card. Azalee fetches and verifies both documents server-side.",
    "human_owner_binding": "After host verification, Azalee sends an approve/reject step to the requested owner email. Approval requires a signed-in, email-verified Azalee account with that exact email. This approval binds the agent to that account.",
    "public_chat_rule": "A prompt, chat message, copied email or pairing code inside a publicly accessible agent conversation is never accepted as proof of bot ownership or owner authorization.",
    "dual_ownership_check": "Credentials are created only after both server-side bot-admin proof and explicit approval by the exact verified human owner account.",
    "status_auth": "X-Enrollment-Secret header only. Query-string secrets are not accepted.",
    "mail_abuse_protection": "Per-IP and per-owner-email rate limits plus pending owner + agent.name dedupe.",
    "callback_url_policy": "callbackUrl must be public HTTPS without credentials, localhost, private IP literals or internal hostnames and must use the verified Agent Card origin."
  },
  "data_minimization": "Hash logs and metadata by default. Do not send raw prompts, passwords, customer records, raw audio, full transcripts or secrets.",
  "endpoints": {
    "agent_start": {
      "method": "POST",
      "url": "https://azalee.garden/api/a2a-start",
      "auth": "none",
      "content_type": "application/json",
      "required_body": {
        "ownerEmail": "owner@company.example",
        "agentCardUrl": "https://agent.company.example/.well-known/agent-card.json"
      },
      "response_fields": [
        "agentStartToken",
        "expiresAt",
        "adminProof",
        "enrollment"
      ],
      "purpose": "Starts a short-lived machine flow. This endpoint does not email the owner and does not create an enrollment until the agent host proves control."
    },
    "bot_admin_proof": {
      "method": "GET",
      "url": "https://<agent-host>/.well-known/azalee-agent-ownership.json",
      "same_origin_requirement": "Must share the origin of https://<agent-host>/.well-known/agent-card.json",
      "required_document": {
        "provider": "azalee",
        "version": 1,
        "challenge": "<challenge-from-agent_start-response>",
        "agentCardUrl": "https://<agent-host>/.well-known/agent-card.json",
        "expiresAt": "<same-short-lived-expiry-from-agent_start-response>"
      }
    },
    "enroll": {
      "method": "POST",
      "url": "https://azalee.garden/api/a2a-enroll",
      "auth": "none; signed agentStartToken plus server-side bot-admin proof",
      "content_type": "application/json",
      "required_fields": [
        "agentStartToken",
        "agentCardUrl",
        "agent.name"
      ],
      "rejected_identity_fallbacks": [
        "ownerEmail without a signed start token",
        "public chat instruction",
        "unverified callback URL"
      ],
      "optional_fields": [
        "agent.clientId",
        "declaredUseCase",
        "riskClassification",
        "callbackUrl",
        "requestedTier (legacy compatibility only; ignored for product entitlement)"
      ],
      "limits": {
        "max_body_bytes": 32768,
        "per_ip": "5 enrollment requests per minute",
        "per_owner_email": "3 requests per hour and 10 requests per day",
        "duplicate_policy": "Only a pending request for the same resolved owner and the same verified Agent Card may be reused. Insecure or mismatched pending requests are superseded."
      },
      "example": {
        "agentStartToken": "<short-lived-token-from-agent_start-endpoint>",
        "agentCardUrl": "https://agent.company.example/.well-known/agent-card.json",
        "agent": {
          "name": "Claims Agent",
          "clientId": "claims-agent"
        },
        "declaredUseCase": "Processes claims and calls approved internal tools.",
        "riskClassification": "limited"
      }
    },
    "status": {
      "method": "GET",
      "url": "https://azalee.garden/api/a2a-enrollment-status?id=<enrollmentId>",
      "auth": "X-Enrollment-Secret: <enrollmentSecret>",
      "legacy_auth": "Query-string secret authentication is not accepted."
    },
    "human_approval": {
      "method": "POST",
      "url": "https://azalee.garden/api/a2a-approve-enrollment",
      "auth": "Authorization: Bearer <human_supabase_access_token>",
      "required_preconditions": [
        "verified bot administrator proof",
        "exact verified owner email/account"
      ],
      "required_body": {
        "enrollmentId": "<uuid>",
        "decision": "approve",
        "billingAcknowledged": true
      },
      "ui_url": "https://azalee.garden/#/approve?id=<enrollmentId>",
      "ui_hint": "The owner receives a login-gated approve/reject page. The backend blocks approval unless the signed-in verified email exactly matches the requested owner and the agent host proof already passed."
    },
    "owner_prebinding_legacy": {
      "method": "POST",
      "url": "https://azalee.garden/api/a2a-owner-binding",
      "auth": "Authorization: Bearer <human_supabase_access_token>",
      "purpose": "Optional advanced pre-binding path retained for controlled integrations. Normal A2A agents should use agent_start instead."
    }
  },
  "supported_connection_paths": {
    "self_hosted_a2a": "Use agent_start, publish the well-known challenge, enroll, then poll after the human owner decision.",
    "hosted_platform": "When a platform cannot publish an Agent Card and ownership proof on a controlled host, connect Azalee from that platform's authenticated admin/developer area through OAuth, an API action or server secret installation instead of public A2A chat pairing."
  },
  "post_approval_credentials": {
    "delivery": "One-time agent polling after dual ownership proof and human approval.",
    "api_ingest": "Authorization: Bearer <apiKey> + { clientId, hash, metadata }",
    "webhook": "POST https://azalee.garden/api/webhook?token=<webhookToken>",
    "hmac_header": "X-Azalee-Signature: t=<unix>,v1=<hmac_sha256_hex>"
  },
  "event_metadata_contract": {
    "statement": "Azalee records tool use when the integrating agent or app sends it as an event. Azalee is an audit log, not a hidden scanner inside the model runtime.",
    "indexed_fields": [
      "event_type",
      "actor_type",
      "actor_id",
      "correlation_id",
      "task_id",
      "status"
    ],
    "recommended_tool_fields": [
      "tool_name",
      "tool_call_id",
      "model",
      "step"
    ],
    "recommended_extra_fields": [
      "session_id",
      "oversight_by",
      "error_type",
      "agent_version",
      "input_sha3",
      "output_sha3"
    ],
    "recommended_event_types": {
      "transparency": [
        "disclosure.shown"
      ],
      "session_and_use_period": [
        "session.started",
        "session.ended"
      ],
      "model_agent_retrieval": [
        "model.call.completed",
        "embedding.completed",
        "retrieval.completed",
        "agent.invoked",
        "agent.handoff",
        "tool.call.completed"
      ],
      "human_oversight": [
        "human.review.requested",
        "human.override",
        "human.approval",
        "human.rejection"
      ],
      "risk_and_safety": [
        "guardrail.triggered",
        "policy.violation",
        "safety.refusal",
        "error.raised"
      ],
      "change_tracking": [
        "agent.config.changed",
        "model.changed",
        "prompt.template.changed"
      ]
    },
    "alignment": "EU AI Act Article 12 record-keeping, Article 50 transparency/disclosure obligations (applicable from 2 August 2026), and OpenTelemetry GenAI semantic conventions.",
    "hashing_contract": "SHA3-256 over canonical JSON (RFC 8785 style: sorted keys, no whitespace). Hashes are independently recomputable from the original event.",
    "example": {
      "event": {
        "hash_this": "tool result or control payload fingerprint source"
      },
      "metadata": {
        "event_type": "tool.call.completed",
        "actor_type": "agent",
        "actor_id": "claims-agent",
        "tool_name": "crm.lookup_customer",
        "tool_call_id": "call_123",
        "model": "gpt-4.1",
        "task_id": "ticket_42",
        "status": "success"
      }
    }
  },
  "docs": "https://azalee.garden/#/docs",
  "human_contact": "namik.hasanovic@azalee.garden"
}
