{
  "openapi": "3.1.0",
  "info": {
    "title": "Fidacy Engine API",
    "version": "1.0.0",
    "summary": "Risk assessment and verifiable verdicts for AP2 / A2A agent payments.",
    "description": "A small, REST-ish surface. JSON in, JSON out. Every call is authenticated with an API key (`x-api-key` header, or `Authorization: Bearer fky_live_...`) and is organization-scoped. The public JWKS and health endpoints need no auth. Internal cron routes (`/internal/*`, CRON_SECRET-gated) are intentionally not part of this public spec.",
    "contact": { "name": "Fidacy", "url": "https://fidacy.com" }
  },
  "servers": [
    { "url": "https://api.fidacy.com", "description": "Production" }
  ],
  "security": [{ "apiKey": [] }],
  "tags": [
    { "name": "Assess", "description": "Score and sign a mandate; read assessments back." },
    { "name": "Agents", "description": "Know-Your-Agent (KYA): principals, agents, keys." },
    { "name": "Mandates", "description": "Read stored mandates." },
    { "name": "Policies", "description": "Rules Engine: draft, backtest, activate." },
    { "name": "Audit", "description": "Hash-chained tamper-evident trail." },
    { "name": "API Keys", "description": "Manage organization API keys." },
    { "name": "Webhooks", "description": "Signed event delivery." },
    { "name": "Public", "description": "Unauthenticated public endpoints." }
  ],
  "paths": {
    "/health": {
      "get": {
        "tags": ["Public"],
        "summary": "Health check",
        "description": "Liveness probe. Public, no auth.",
        "security": [],
        "responses": {
          "200": {
            "description": "Service is up.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "ok" },
                    "service": { "type": "string", "example": "fidacy-engine" },
                    "ap2": { "type": "string", "description": "AP2 protocol version." }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/.well-known/jwks.json": {
      "get": {
        "tags": ["Public"],
        "summary": "Public JWKS",
        "description": "The public signing key set (EdDSA / OKP Ed25519). Use it to verify a `riskPayloadJws` offline — no auth, cacheable per `kid` (`cache-control: public, max-age=3600`).",
        "security": [],
        "responses": {
          "200": {
            "description": "The JSON Web Key Set.",
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/Jwks" }
              }
            }
          },
          "503": {
            "description": "Signing key temporarily unavailable.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/v1/assess": {
      "post": {
        "tags": ["Assess"],
        "summary": "Assess a mandate",
        "operationId": "assess",
        "description": "The core call. Validates the mandate, runs KYA -> policy -> risk -> sign -> audit, and returns the decision plus the rich outcome and the signed Risk Payload (`riskPayloadJws`). Requires scope `assess:write`. Engage A2A with an `A2A-Version` header or an `a2a` block. Idempotent by the mandate's canonical content hash.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/AssessRequest" },
              "example": {
                "mandate": {
                  "vct": "mandate.payment.1",
                  "transaction_id": "5f3c...",
                  "payee": { "id": "merchant_42", "name": "Acme Corp" },
                  "payment_amount": { "amount": 4299, "currency": "EUR" },
                  "payment_instrument": { "id": "pi_1", "type": "card" }
                },
                "kind": "ap2_payment"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The verdict, the signed Risk Payload, and the rich outcome.",
            "headers": {
              "Server-Timing": {
                "description": "Per-stage latency (kya/policy/risk/sign/persist).",
                "schema": { "type": "string" }
              },
              "x-fidacy-server-timing": {
                "description": "Duplicate of Server-Timing preserved through edge proxies.",
                "schema": { "type": "string" }
              }
            },
            "content": {
              "application/json": {
                "schema": { "$ref": "#/components/schemas/AssessResponse" }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "422": {
            "description": "The mandate failed schema validation.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "500": {
            "description": "Internal error. Never returns approve; the safe state is review.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    },
    "/v1/assessments": {
      "get": {
        "tags": ["Assess"],
        "summary": "List assessments",
        "operationId": "listAssessments",
        "description": "Paginated list (cursor / keyset). Requires scope `assess:read`.",
        "parameters": [
          { "name": "status", "in": "query", "schema": { "type": "string", "enum": ["approve", "approved", "review", "deny", "denied"] }, "description": "Filter by decision." },
          { "name": "agent", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Filter by agent id." },
          { "name": "kind", "in": "query", "schema": { "$ref": "#/components/schemas/ActionKind" }, "description": "Filter by action kind." },
          { "name": "from", "in": "query", "schema": { "type": "string", "format": "date-time" }, "description": "Created at >= this time." },
          { "name": "to", "in": "query", "schema": { "type": "string", "format": "date-time" }, "description": "Created at <= this time." },
          { "name": "cursor", "in": "query", "schema": { "type": "string" }, "description": "Opaque pagination cursor (from `next_cursor`)." },
          { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 100, "default": 25 }, "description": "Page size." }
        ],
        "responses": {
          "200": {
            "description": "A page of compact assessment summaries.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "object": { "type": "string", "const": "list" },
                    "data": { "type": "array", "items": { "$ref": "#/components/schemas/AssessmentSummary" } },
                    "has_more": { "type": "boolean" },
                    "next_cursor": { "type": ["string", "null"] }
                  }
                }
              }
            }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    },
    "/v1/assessments/{id}": {
      "get": {
        "tags": ["Assess"],
        "summary": "Get an assessment",
        "operationId": "getAssessment",
        "description": "The full rich outcome, reconstructed deterministically from the stored record (replay invariant). Requires scope `assess:read`.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Assessment id." }
        ],
        "responses": {
          "200": {
            "description": "The rich outcome object.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Outcome" } } }
          },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    },
    "/v1/principals": {
      "post": {
        "tags": ["Agents"],
        "summary": "Create a principal",
        "description": "Register the accountable principal. Requires scope `agents:write`.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object" } } } },
        "responses": {
          "201": { "description": "Created." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      },
      "get": {
        "tags": ["Agents"],
        "summary": "List principals",
        "description": "Requires scope `agents:read`.",
        "responses": {
          "200": { "description": "A list of principals." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/v1/principals/{id}/erase": {
      "post": {
        "tags": ["Agents"],
        "summary": "Erase a principal (GDPR)",
        "description": "Crypto-erase / redact a principal's personal data. Requires scope `gdpr:erase`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "Erased." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/agents": {
      "post": {
        "tags": ["Agents"],
        "summary": "Create an agent",
        "description": "Register an agent that represents a principal. Requires scope `agents:write`.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object" } } } },
        "responses": {
          "201": { "description": "Created." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      },
      "get": {
        "tags": ["Agents"],
        "summary": "List agents",
        "description": "Requires scope `agents:read`.",
        "responses": {
          "200": { "description": "A list of agents." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/v1/agents/{id}": {
      "get": {
        "tags": ["Agents"],
        "summary": "Get an agent",
        "description": "Requires scope `agents:read`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "The agent." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "patch": {
        "tags": ["Agents"],
        "summary": "Update an agent",
        "description": "Requires scope `agents:write`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object" } } } },
        "responses": {
          "200": { "description": "Updated." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/agents/{id}/trust-history": {
      "get": {
        "tags": ["Agents"],
        "summary": "Agent trust history",
        "description": "The trust-score timeline for an agent. Requires scope `agents:read`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "Trust history." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/agents/{id}/card-status": {
      "get": {
        "tags": ["Agents"],
        "summary": "Agent card verification status",
        "description": "The A2A Agent Card verification status for an agent. Requires scope `agents:read`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "Card status." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/agents/verify-card": {
      "post": {
        "tags": ["Agents"],
        "summary": "Verify an A2A Agent Card",
        "description": "Verify an A2A Agent Card and bind it to an agent. Requires scope `agents:write`.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object" } } } },
        "responses": {
          "200": { "description": "Verification result." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/v1/agents/{id}/keys": {
      "post": {
        "tags": ["Agents"],
        "summary": "Add a public key to an agent",
        "description": "Register a public key the agent signs with (stored with its RFC 7638 thumbprint). Requires scope `agents:write`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object" } } } },
        "responses": {
          "201": { "description": "Key registered." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      },
      "get": {
        "tags": ["Agents"],
        "summary": "List an agent's keys",
        "description": "Requires scope `agents:read`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "The agent's keys." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/agents/{id}/keys/{keyId}/revoke": {
      "post": {
        "tags": ["Agents"],
        "summary": "Revoke an agent key",
        "description": "Requires scope `agents:write`.",
        "parameters": [
          { "name": "id", "in": "path", "required": true, "schema": { "type": "string" } },
          { "name": "keyId", "in": "path", "required": true, "schema": { "type": "string" } }
        ],
        "responses": {
          "200": { "description": "Revoked." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/mandates": {
      "get": {
        "tags": ["Mandates"],
        "summary": "List mandates",
        "description": "Read the mandates the engine has stored and assessed. Requires scope `assess:read`.",
        "responses": {
          "200": { "description": "A list of mandates." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/v1/mandates/{id}": {
      "get": {
        "tags": ["Mandates"],
        "summary": "Get a mandate",
        "description": "Requires scope `assess:read`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "The mandate." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/policies": {
      "get": {
        "tags": ["Policies"],
        "summary": "List policies",
        "description": "Requires scope `policy:read`.",
        "responses": {
          "200": { "description": "A list of policies." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      },
      "post": {
        "tags": ["Policies"],
        "summary": "Create a policy",
        "description": "Create a draft policy (optionally activate). Requires scope `policy:write`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "type": "object" },
              "example": {
                "name": "eu-cards-v3",
                "rules": {
                  "max_amount": 1000000,
                  "currencies": ["EUR", "GBP"],
                  "geo": { "allow": ["EU"] },
                  "velocity": { "window": "1h", "max": 20 }
                },
                "activate": false
              }
            }
          }
        },
        "responses": {
          "201": { "description": "Created." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/v1/policies/{id}": {
      "get": {
        "tags": ["Policies"],
        "summary": "Get a policy",
        "description": "Requires scope `policy:read`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "The policy." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/policies/{id}/activate": {
      "post": {
        "tags": ["Policies"],
        "summary": "Activate a policy",
        "description": "Make this the one active policy for the org. Requires scope `policy:write`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "Activated." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/policies/{id}/backtest": {
      "post": {
        "tags": ["Policies"],
        "summary": "Backtest a policy",
        "description": "Replay a draft policy against your assessment history. Requires scope `policy:read`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "Backtest results." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/audit": {
      "get": {
        "tags": ["Audit"],
        "summary": "List the audit trail",
        "description": "The hash-chained, tamper-evident trail. Requires scope `audit:read`.",
        "responses": {
          "200": { "description": "Audit entries." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/v1/audit/verify": {
      "get": {
        "tags": ["Audit"],
        "summary": "Verify trail integrity",
        "description": "Recompute every entry hash and check the chain links, returning the first break (if any). Deterministic and reproducible offline. Requires scope `audit:read`.",
        "responses": {
          "200": { "description": "Verification report." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/v1/api-keys": {
      "post": {
        "tags": ["API Keys"],
        "summary": "Create an API key",
        "description": "The plaintext key is returned ONCE. Requires scope `keys:write`.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object" } } } },
        "responses": {
          "201": { "description": "Created; plaintext key returned once." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      },
      "get": {
        "tags": ["API Keys"],
        "summary": "List API keys",
        "description": "Metadata only (never the secret). Requires scope `keys:read`.",
        "responses": {
          "200": { "description": "A list of API key metadata." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/v1/api-keys/{id}/revoke": {
      "post": {
        "tags": ["API Keys"],
        "summary": "Revoke an API key",
        "description": "Requires scope `keys:write`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "Revoked." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/webhook-endpoints": {
      "post": {
        "tags": ["Webhooks"],
        "summary": "Register a webhook endpoint",
        "description": "Register a signed event delivery target. Requires scope `webhooks:write`.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object" } } } },
        "responses": {
          "201": { "description": "Registered." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      },
      "get": {
        "tags": ["Webhooks"],
        "summary": "List webhook endpoints",
        "description": "Requires scope `webhooks:read`.",
        "responses": {
          "200": { "description": "A list of endpoints." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/v1/webhook-endpoints/{id}": {
      "delete": {
        "tags": ["Webhooks"],
        "summary": "Delete a webhook endpoint",
        "description": "Requires scope `webhooks:write`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "Deleted." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/webhook-endpoints/{id}/deliveries": {
      "get": {
        "tags": ["Webhooks"],
        "summary": "List deliveries for an endpoint",
        "description": "Delivery attempts and their status. Requires scope `webhooks:read`.",
        "parameters": [{ "name": "id", "in": "path", "required": true, "schema": { "type": "string" } }],
        "responses": {
          "200": { "description": "Delivery records." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" }
        }
      }
    },
    "/v1/webhooks/dispatch": {
      "post": {
        "tags": ["Webhooks"],
        "summary": "Dispatch queued webhooks",
        "description": "Trigger delivery of pending webhook events. Requires scope `webhooks:write`.",
        "responses": {
          "200": { "description": "Dispatch result." },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" }
        }
      }
    },
    "/v1/me": {
      "get": {
        "tags": ["Assess"],
        "summary": "Caller context",
        "description": "The authenticated caller's organization id, actor, and granted scopes.",
        "responses": {
          "200": {
            "description": "Caller context.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "orgId": { "type": "string" },
                    "actor": { "type": "object" },
                    "scopes": { "type": "array", "items": { "type": "string" } }
                  }
                }
              }
            }
          },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "503": { "$ref": "#/components/responses/Unavailable" }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "x-api-key",
        "description": "Organization API key. `Authorization: Bearer fky_live_...` is also accepted."
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Malformed request, unknown mandate type, or A2A version mismatch.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unauthorized": {
        "description": "Missing or invalid credential.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Forbidden": {
        "description": "The key lacks the required scope.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "NotFound": {
        "description": "Not found in your organization.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      },
      "Unavailable": {
        "description": "Database or signing key temporarily unavailable.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string", "description": "Machine-readable error code." },
          "details": { "description": "Optional structured validation details." }
        },
        "required": ["error"]
      },
      "ActionKind": {
        "type": "string",
        "enum": ["ap2_payment", "message_send", "voice_call", "custom"],
        "default": "ap2_payment",
        "description": "Action supertype selecting the validation path."
      },
      "Amount": {
        "type": "object",
        "description": "ISO 4217 amount in integer minor units.",
        "properties": {
          "amount": { "type": "integer", "description": "Integer minor units (e.g. 4299 = EUR 42.99)." },
          "currency": { "type": "string", "description": "ISO 4217 code, e.g. EUR." }
        },
        "required": ["amount", "currency"]
      },
      "PaymentMandate": {
        "type": "object",
        "description": "AP2 Payment Mandate (vct mandate.payment.1). Additional AP2 fields allowed.",
        "properties": {
          "vct": { "type": "string", "const": "mandate.payment.1" },
          "transaction_id": { "type": "string", "description": "base64url hash identifying the checkout." },
          "payee": { "type": "object", "description": "The merchant receiving the payment." },
          "payment_amount": { "$ref": "#/components/schemas/Amount" },
          "payment_instrument": { "type": "object", "description": "The payment instrument used." },
          "execution_date": { "type": "string", "description": "ISO 8601 execution date; immediate when absent." },
          "risk_data": { "type": "object", "description": "Risk signals; Fidacy injects its signed payload here on response." }
        },
        "required": ["vct", "transaction_id", "payee", "payment_amount", "payment_instrument"]
      },
      "AssessRequest": {
        "type": "object",
        "properties": {
          "mandate": {
            "description": "The AP2 mandate / action. For ap2_payment this is a PaymentMandate (or other AP2 mandate type).",
            "oneOf": [
              { "$ref": "#/components/schemas/PaymentMandate" },
              { "type": "object" }
            ]
          },
          "kind": { "$ref": "#/components/schemas/ActionKind" },
          "mandateType": {
            "type": "string",
            "enum": ["checkout", "payment", "open_checkout", "open_payment"],
            "description": "AP2 type; derived from the vct when omitted (ap2_payment only)."
          },
          "a2a": {
            "type": "object",
            "description": "Optional A2A context binding the assessment to a Task lifecycle.",
            "properties": {
              "task_id": { "type": "string" },
              "context_id": { "type": "string" },
              "agent_card_ref": { "type": "string" },
              "a2a_version": { "type": "string" }
            }
          },
          "idempotency_key": { "type": "string", "description": "Optional explicit idempotency key; echoed back." }
        },
        "required": ["mandate"]
      },
      "Decision": {
        "type": "string",
        "enum": ["approve", "review", "deny"],
        "description": "The verdict. review is also the safe fallback on any internal fault."
      },
      "AssessResponse": {
        "type": "object",
        "properties": {
          "decision": { "$ref": "#/components/schemas/Decision" },
          "score": { "type": "integer", "minimum": 0, "maximum": 100, "description": "Risk score 0-100." },
          "assessmentId": { "type": "string", "description": "First-class assessment id; read it back via GET /v1/assessments/{id}." },
          "mandateId": { "type": "string", "description": "The stored mandate id." },
          "riskPayloadJws": { "type": "string", "description": "The signed Risk Payload as a compact JWS (EdDSA). Verify offline against the public JWKS." },
          "mandate": { "type": "object", "description": "Your mandate with risk_data injected — forward this downstream." },
          "outcome": { "$ref": "#/components/schemas/Outcome" }
        },
        "required": ["decision", "score", "assessmentId", "mandateId", "riskPayloadJws", "outcome"]
      },
      "AssessmentSummary": {
        "type": "object",
        "description": "Compact assessment record returned by the list endpoint.",
        "properties": {
          "id": { "type": "string" },
          "object": { "type": "string", "const": "assessment" },
          "created": { "type": "string" },
          "kind": { "$ref": "#/components/schemas/ActionKind" },
          "livemode": { "type": "boolean" },
          "decision": { "$ref": "#/components/schemas/Decision" },
          "risk_level": { "type": "string", "enum": ["normal", "elevated", "highest"] },
          "risk_score": { "type": "integer" },
          "reason": { "type": "string" },
          "agent_id": { "type": ["string", "null"] }
        }
      },
      "Outcome": {
        "type": "object",
        "description": "The rich, versioned outcome object — identical from /v1/assess and GET /v1/assessments/{id}.",
        "properties": {
          "object": { "type": "string", "const": "assessment" },
          "id": { "type": "string" },
          "created": { "type": "string" },
          "livemode": { "type": "boolean" },
          "kind": { "$ref": "#/components/schemas/ActionKind" },
          "outcome": {
            "type": "object",
            "properties": {
              "decision": { "$ref": "#/components/schemas/Decision" },
              "risk_level": { "type": "string", "enum": ["normal", "elevated", "highest"] },
              "risk_score": { "type": "integer" },
              "reason": { "type": "string" },
              "policy_version": { "type": "integer" }
            }
          },
          "confidences": {
            "type": "object",
            "properties": {
              "agent_identity": { "type": "number" },
              "mandate_validity": { "type": "number" },
              "policy_adherence": { "type": "number" },
              "behavioral_risk": { "type": "number" },
              "recipient_risk": { "type": "number" }
            }
          },
          "signals": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "category": { "type": "string" },
                "type": { "type": "string" },
                "severity": { "type": "string" }
              }
            }
          },
          "rejection_reasons": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "key": { "type": "string" },
                "category": { "type": "string" },
                "description": { "type": "string" }
              }
            }
          },
          "risk_payload": {
            "type": "object",
            "properties": {
              "jws": { "type": "string" },
              "kid": { "type": "string" },
              "alg": { "type": "string", "const": "EdDSA" },
              "verify_url": { "type": "string", "description": "The JWKS URL to verify against." }
            }
          },
          "audit": {
            "type": "object",
            "description": "Pointer into the tamper-evident hash-chained log.",
            "properties": {
              "entry_id": { "type": "string" },
              "sequence": { "type": "integer" },
              "status": { "type": "string", "enum": ["pending", "anchored"] }
            }
          },
          "refinement": {
            "type": ["object", "null"],
            "properties": { "status": { "type": "string" } }
          },
          "agent": {
            "type": ["object", "null"],
            "properties": {
              "id": { "type": "string" },
              "trust_score": { "type": "integer" },
              "risk_tier": { "type": "string" }
            }
          },
          "latency_ms": { "type": "integer" }
        }
      },
      "Jwks": {
        "type": "object",
        "description": "JSON Web Key Set with the public EdDSA (OKP / Ed25519) verifying key(s).",
        "properties": {
          "keys": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "kty": { "type": "string", "example": "OKP" },
                "crv": { "type": "string", "example": "Ed25519" },
                "x": { "type": "string", "description": "Public key, base64url." },
                "kid": { "type": "string", "description": "Key id matching the JWS protected header." },
                "alg": { "type": "string", "example": "EdDSA" },
                "use": { "type": "string", "example": "sig" }
              }
            }
          }
        },
        "required": ["keys"]
      }
    }
  }
}
