{
  "openapi": "3.1.0",
  "info": {
    "title": "AEC Agent API",
    "version": "0.1.0",
    "summary": "Clause-cited regulation evidence and library retrieval for AI agents and servers.",
    "description": "The evidence API (`/api/v1/health`, `/contract`, `/catalogue`, `/sources`, `/clauses`) and the library retrieval API (`/api/v1/graphrag`), described as one document. Every endpoint except the health check takes a bearer credential issued to an approved member. The MCP connector at `/api/mcp` is described at `/developers` and `/.well-known/mcp.json`.\n\n## Governed Evidence Query API\nEvidence-linked research support only. Nothing returned by this interface is legal advice, a\ncompliance determination or professional sign-off. Refer disputed evidence to editorial review.\n\n**Availability.** This pilot interface is provided on a best-effort basis with no uptime\ncommitment. When the evidence store cannot be reached the interface answers `UNAVAILABLE` and\nnever serves partial, cached or previously retrieved evidence.\n\n**Stability.** This contract is UNSTABLE during the closed pilot. A breaking change is recorded\nin `x-contract-changelog` and announced to pilot clients before it takes effect. It freezes at the\nearlier of the first client outside the closed pilot being onboarded or Phase 5 exit. After the\nfreeze a breaking change ships as a new contract version served alongside the previous one for a\nstated overlap window.\n\n**Client conformance rule.** A client MUST treat any `outcome` value it does not recognise as a\nrefusal that surfaces no evidence. This is what allows new client-boundary outcomes to be added\nwithout a breaking change.\n\n**Outcome authority.** The `outcome` field of the body is authoritative. The HTTP status is a\nhint for generic tooling.\n\n**Read only.** Every operation is a `GET`. The interface accepts no request body. Any query\nparameter not declared here is refused as `INVALID_REQUEST`.\n\n**Order of evaluation.** Authentication, then request limits, then request validation, then\naccess and currentness. An unauthenticated caller learns nothing beyond `UNAUTHENTICATED`.\n\n\n## AEC Agent library API (GraphRAG)\nREST access to the regulation libraries, for servers and AI agents. Unstable until the pilot\ncontract freezes; breaking changes are recorded in `x-contract-changelog`.\n\n**A key acts as its owner.** An API key opens exactly the libraries its owner may open: the same\nper-library assignments (direct, or through an open organisation), the same administrator\nrule, and the same withdrawals, re-checked on every request. The owner's current status\ndecides, not anything stored on the key, so a disabled owner's keys stop on their next\nrequest. A key may additionally be limited, when it is issued, to a list of libraries; that\nonly narrows what the owner may open.\n\n**Client conformance rule.** A client MUST treat any `outcome` it does not recognise as a\nrefusal that surfaces no content.\n\n**Never from a browser.** Use the key from a server or agent runtime. It is shown to the\nadministrator once when issued and cannot be read back.\n",
    "contact": {
      "name": "SPAIRL",
      "url": "https://aec-agent.spairl.si/contact"
    }
  },
  "servers": [
    {
      "url": "https://aec-agent.spairl.si"
    }
  ],
  "security": [
    {
      "pilotCredential": []
    }
  ],
  "x-contract-changelog": [
    {
      "version": "0.1.0",
      "date": "2026-09-21",
      "breaking": false,
      "change": "Initial draft of the client contract."
    }
  ],
  "x-graphrag-contract-changelog": [
    {
      "version": "graphrag/1",
      "date": "2026-10-07",
      "breaking": true,
      "change": "Access follows the owner's dataset assignments, as the web does. Before, every key opened every shared library. Libraries a key may not open are no longer returned in `libraries`; they appear by name and region in the new `listOnly` array (additive). Retrieval of a library that is not open still returns ACCESS_DENIED (403)."
    },
    {
      "version": "graphrag/1",
      "date": "2026-10-08",
      "breaking": false,
      "change": "Under the full-graph access model (feature 018) access is all or nothing. A key whose owner has full-graph access sees every library in the live build in `libraries`. Any other key sees every library in `listOnly` with its `pages` and `counts` (additive) and a `message` that says to ask an administrator or subscribe; `POST /api/v1/graphrag/retrieve` answers `NOT_ENTITLED` (403, additive) with the same `message`. A blocked or unknown build answers `UNAVAILABLE` (503)."
    }
  ],
  "paths": {
    "/api/v1/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "Report whether the interface can currently serve requests.",
        "description": "Operational endpoint. Requires no credential. Discloses no evidence, source, entitlement or\ncaller information, carries no research-support notice and records no access event.\n",
        "security": [],
        "parameters": [
          {
            "$ref": "#/components/parameters/CorrelationId"
          }
        ],
        "responses": {
          "200": {
            "description": "The interface can serve requests.",
            "headers": {
              "X-Correlation-Id": {
                "$ref": "#/components/headers/XCorrelationId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          },
          "503": {
            "description": "The interface cannot currently serve requests.",
            "headers": {
              "X-Correlation-Id": {
                "$ref": "#/components/headers/XCorrelationId"
              },
              "Retry-After": {
                "$ref": "#/components/headers/RetryAfter"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/contract": {
      "get": {
        "operationId": "getContract",
        "summary": "Return the exact contract document this server conforms to.",
        "description": "Serves this document as JSON, including its version, stability status and change history.\nAny authenticated pilot role may read it.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/CorrelationId"
          }
        ],
        "responses": {
          "200": {
            "description": "The contract document.",
            "headers": {
              "X-Correlation-Id": {
                "$ref": "#/components/headers/XCorrelationId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ContractDocument"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/catalogue": {
      "get": {
        "operationId": "listCatalogue",
        "summary": "List the sources the caller's entitlement covers.",
        "description": "Metadata only. No clause text and no clause anchors: list anchors with `listClauseIndex`.\nA caller entitled to nothing receives an empty page, not a refusal. A caller whose role holds\nno retrieval capability receives `ACCESS_DENIED`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/CorrelationId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "One page of the catalogue.",
            "headers": {
              "X-Correlation-Id": {
                "$ref": "#/components/headers/XCorrelationId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CatalogueResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/AccessDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/sources/{sourceId}/evidence": {
      "get": {
        "operationId": "retrieveSourceEvidence",
        "summary": "Retrieve the current published evidence of a source.",
        "description": "Returns clause text with one complete source receipt per clause, in document order, in\nbounded pages. The answer is atomic per version: it is supported only if every clause of the\ncurrent version has a complete receipt. Supply `ifMarker` to ask whether previously retrieved\nevidence is still current without retrieving it again. `ifMarker` cannot be combined with\n`cursor`.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/CorrelationId"
          },
          {
            "$ref": "#/components/parameters/SourceId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          },
          {
            "$ref": "#/components/parameters/IfMarker"
          }
        ],
        "responses": {
          "200": {
            "description": "Supported evidence, an unchanged marker, or no supported answer.",
            "headers": {
              "X-Correlation-Id": {
                "$ref": "#/components/headers/XCorrelationId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/SupportedEvidenceResponse"
                    },
                    {
                      "$ref": "#/components/schemas/UnchangedResponse"
                    },
                    {
                      "$ref": "#/components/schemas/NoSupportedAnswerResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/AccessDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/sources/{sourceId}/clause-index": {
      "get": {
        "operationId": "listClauseIndex",
        "summary": "List the clause anchors of a source's current published version.",
        "description": "Metadata only, in document order, in bounded pages. Carries no clause text. A cursor is bound\nto the version it started on and is refused as `INVALID_REQUEST` once that version stops being\ncurrent.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/CorrelationId"
          },
          {
            "$ref": "#/components/parameters/SourceId"
          },
          {
            "$ref": "#/components/parameters/Limit"
          },
          {
            "$ref": "#/components/parameters/Cursor"
          }
        ],
        "responses": {
          "200": {
            "description": "One page of the clause index, or no supported answer.",
            "headers": {
              "X-Correlation-Id": {
                "$ref": "#/components/headers/XCorrelationId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/ClauseIndexResponse"
                    },
                    {
                      "$ref": "#/components/schemas/NoSupportedAnswerResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/AccessDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/clauses/{clauseAnchor}": {
      "get": {
        "operationId": "retrieveClauseEvidence",
        "summary": "Retrieve one clause of the current published version by its exact anchor.",
        "description": "A clause anchor identifies a clause of one specific source version. If that version is no\nlonger current the answer is `NO_SUPPORTED_ANSWER`. The interface never substitutes the same\nclause label from a newer version.\n",
        "parameters": [
          {
            "$ref": "#/components/parameters/CorrelationId"
          },
          {
            "$ref": "#/components/parameters/ClauseAnchor"
          },
          {
            "$ref": "#/components/parameters/IfMarker"
          }
        ],
        "responses": {
          "200": {
            "description": "Supported evidence, an unchanged marker, or no supported answer.",
            "headers": {
              "X-Correlation-Id": {
                "$ref": "#/components/headers/XCorrelationId"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/SupportedEvidenceResponse"
                    },
                    {
                      "$ref": "#/components/schemas/UnchangedResponse"
                    },
                    {
                      "$ref": "#/components/schemas/NoSupportedAnswerResponse"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/InvalidRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthenticated"
          },
          "403": {
            "$ref": "#/components/responses/AccessDenied"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/v1/graphrag/libraries": {
      "get": {
        "operationId": "listGraphRagLibraries",
        "summary": "The libraries this key can open, and those it can only see listed",
        "description": "Lists the regulation libraries in the live build. A key with full-graph access sees every\nlibrary in `libraries`, most used first. Any other key sees every library in `listOnly`, by\ntitle and region, with a `message` that says to ask an administrator or subscribe. Call this\nfirst, to learn what a retrieval can search. Needs a bearer key; carries no request body.\n",
        "responses": {
          "200": {
            "description": "GRAPHRAG_CATALOGUE",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "outcome",
                    "libraries",
                    "listOnly",
                    "correlationId"
                  ],
                  "properties": {
                    "outcome": {
                      "const": "GRAPHRAG_CATALOGUE"
                    },
                    "libraries": {
                      "type": "array",
                      "description": "Libraries the key can open, most used first, then by title.",
                      "items": {
                        "$ref": "#/components/schemas/Library"
                      }
                    },
                    "listOnly": {
                      "type": "array",
                      "description": "Libraries that exist but are not open to this key. Name and region only; nothing here opens them.",
                      "items": {
                        "type": "object",
                        "required": [
                          "title",
                          "region"
                        ],
                        "properties": {
                          "title": {
                            "type": "string"
                          },
                          "region": {
                            "type": "string"
                          },
                          "pages": {
                            "type": "integer",
                            "description": "Present for a catalogue-only key."
                          },
                          "counts": {
                            "type": "object",
                            "additionalProperties": {
                              "type": "integer"
                            },
                            "description": "Present for a catalogue-only key."
                          }
                        }
                      }
                    },
                    "message": {
                      "type": "string",
                      "description": "Present for a catalogue-only key: ask your administrator or subscribe to open the libraries."
                    },
                    "correlationId": {
                      "type": "string"
                    },
                    "notice": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Refusal"
          },
          "403": {
            "$ref": "#/components/responses/Refusal"
          },
          "429": {
            "$ref": "#/components/responses/GraphRagRateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    },
    "/api/v1/graphrag/retrieve": {
      "post": {
        "operationId": "retrieveGraphRag",
        "summary": "Retrieve passages and bounded graph context from libraries the key can open",
        "description": "Searches the libraries the key can open for a question or a clause identifier and returns\nquoted passages with their citations, plus separately sourced supporting context. `mode`\nchooses exact, keyword or hybrid retrieval (`AUTO` picks); `versionIds` narrows the search\nto chosen libraries, and `kinds` to sections, entities, tables or figures. Answers\n`ACCESS_DENIED` (403) for a library that is not open to the key, `NOT_ENTITLED` (403) for a\nkey without full-graph access, and `UNAVAILABLE` (503) while the build is blocked. Never\nsend drawing contents; send the regulation question only.\n",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "query"
                ],
                "properties": {
                  "query": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "versionIds": {
                    "type": "array",
                    "maxItems": 20,
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "description": "Empty or absent searches every library the key can open."
                  },
                  "mode": {
                    "enum": [
                      "AUTO",
                      "WORDS",
                      "HYBRID"
                    ],
                    "description": "AUTO uses fast identifiers or hybrid retrieval with a labelled keyword fallback. HYBRID requires a ready matching index. WORDS retains keyword retrieval."
                  },
                  "kinds": {
                    "type": "array",
                    "items": {
                      "enum": [
                        "sections",
                        "entities",
                        "tables",
                        "figures"
                      ]
                    }
                  },
                  "limit": {
                    "type": "integer",
                    "minimum": 1,
                    "maximum": 20
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "GRAPHRAG_RESULTS",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "outcome",
                    "results",
                    "correlationId"
                  ],
                  "properties": {
                    "outcome": {
                      "const": "GRAPHRAG_RESULTS"
                    },
                    "results": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "retrieval": {
                      "$ref": "#/components/schemas/RetrievalMetadata"
                    },
                    "supportingContext": {
                      "type": "array",
                      "description": "Separately sourced context linked to a returned seed. Candidate similarity links do not establish legal precedence.",
                      "items": {
                        "type": "object"
                      }
                    },
                    "correlationId": {
                      "type": "string"
                    },
                    "notice": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Refusal"
          },
          "401": {
            "$ref": "#/components/responses/Refusal"
          },
          "403": {
            "description": "ACCESS_DENIED, including a library that is not open to this key or a forged version id. NOT_ENTITLED (with a message) under the full-graph model for a key without full-graph access.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refusal"
                }
              }
            }
          },
          "429": {
            "$ref": "#/components/responses/GraphRagRateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Refusal"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "pilotCredential": {
        "type": "http",
        "scheme": "bearer",
        "description": "A platform-issued pilot credential. Disabled unless the operator explicitly enables the\npilot credential scheme. Issued and revoked by an operator procedure, never through this\ninterface.\n"
      }
    },
    "headers": {
      "XCorrelationId": {
        "description": "The correlation identifier used for this request. Equal to the body value.",
        "schema": {
          "$ref": "#/components/schemas/CorrelationId"
        }
      },
      "RetryAfter": {
        "description": "Whole seconds to wait before retrying. Equal to `retryAfterSeconds` in the body.",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      }
    },
    "parameters": {
      "CorrelationId": {
        "name": "X-Correlation-Id",
        "in": "header",
        "required": false,
        "description": "Optional caller-supplied correlation identifier. If absent or malformed the server generates\none. Uniqueness is not enforced.\n",
        "schema": {
          "$ref": "#/components/schemas/CorrelationId"
        }
      },
      "SourceId": {
        "name": "sourceId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string",
          "format": "uuid"
        }
      },
      "ClauseAnchor": {
        "name": "clauseAnchor",
        "in": "path",
        "required": true,
        "description": "`<source-version-id>:<canonical-label>`. The colon may be sent literally or as %3A.",
        "schema": {
          "$ref": "#/components/schemas/ClauseAnchor"
        }
      },
      "Limit": {
        "name": "limit",
        "in": "query",
        "required": false,
        "description": "Desired page size. The server clamps it to its configured maximum and never refuses a large\nvalue. The page size actually used is reported in `page.size`.\n",
        "schema": {
          "type": "integer",
          "minimum": 1
        }
      },
      "Cursor": {
        "name": "cursor",
        "in": "query",
        "required": false,
        "description": "An opaque continuation value from a previous page. Do not construct or alter it.",
        "schema": {
          "type": "string",
          "minLength": 1,
          "maxLength": 1024,
          "pattern": "^c1\\.[A-Za-z0-9_-]+$"
        }
      },
      "IfMarker": {
        "name": "ifMarker",
        "in": "query",
        "required": false,
        "description": "A revalidation marker from a previous supported response. If it still identifies the current\nversion the response is `UNCHANGED` and carries no evidence.\n",
        "schema": {
          "$ref": "#/components/schemas/RevalidationMarker"
        }
      }
    },
    "responses": {
      "InvalidRequest": {
        "description": "The request is malformed. Names only the offending field.",
        "headers": {
          "X-Correlation-Id": {
            "$ref": "#/components/headers/XCorrelationId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/InvalidRequestResponse"
            }
          }
        }
      },
      "Unauthenticated": {
        "description": "The request carries no valid credential.",
        "headers": {
          "X-Correlation-Id": {
            "$ref": "#/components/headers/XCorrelationId"
          },
          "WWW-Authenticate": {
            "description": "The challenge, always `Bearer`.",
            "schema": {
              "type": "string",
              "const": "Bearer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UnauthenticatedResponse"
            }
          }
        }
      },
      "AccessDenied": {
        "description": "The caller is authenticated but lacks entitlement. Reveals nothing about whether the\nrequested source or clause exists.\n",
        "headers": {
          "X-Correlation-Id": {
            "$ref": "#/components/headers/XCorrelationId"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/AccessDeniedResponse"
            }
          }
        }
      },
      "RateLimited": {
        "description": "The client has exceeded its request limit. Distinct from an access denial.",
        "headers": {
          "X-Correlation-Id": {
            "$ref": "#/components/headers/XCorrelationId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/RateLimitedResponse"
            }
          }
        }
      },
      "Unavailable": {
        "description": "The interface cannot serve this request. Distinct from `NO_SUPPORTED_ANSWER`: it says nothing\nabout whether evidence exists.\n",
        "headers": {
          "X-Correlation-Id": {
            "$ref": "#/components/headers/XCorrelationId"
          },
          "Retry-After": {
            "$ref": "#/components/headers/RetryAfter"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/UnavailableResponse"
            }
          }
        }
      },
      "Refusal": {
        "description": "A refusal. The outcome is authoritative; the status is a hint.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Refusal"
            }
          }
        }
      },
      "GraphRagRateLimited": {
        "description": "RATE_LIMITED. Retry after the interval in the Retry-After header.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Refusal"
            }
          }
        }
      }
    },
    "schemas": {
      "Outcome": {
        "type": "string",
        "enum": [
          "SUPPORTED_EVIDENCE",
          "CATALOGUE",
          "CLAUSE_INDEX",
          "UNCHANGED",
          "NO_SUPPORTED_ANSWER",
          "INVALID_REQUEST",
          "UNAUTHENTICATED",
          "ACCESS_DENIED",
          "RATE_LIMITED",
          "UNAVAILABLE"
        ]
      },
      "NoSupportedAnswerReason": {
        "description": "A rule name, never evidence.",
        "type": "string",
        "enum": [
          "NO_CURRENT_PUBLISHED_VERSION",
          "UPDATE_PENDING_REVIEW",
          "RIGHTS_WITHDRAWN",
          "SOURCE_RIGHT_NOT_ACTIVE",
          "RECEIPT_INCOMPLETE"
        ]
      },
      "CatalogueStatus": {
        "type": "string",
        "enum": [
          "SUPPORTED",
          "NO_CURRENT_PUBLISHED_VERSION",
          "UPDATE_PENDING_REVIEW",
          "RIGHTS_WITHDRAWN",
          "SOURCE_RIGHT_NOT_ACTIVE",
          "RECEIPT_INCOMPLETE"
        ]
      },
      "CorrelationId": {
        "type": "string",
        "minLength": 8,
        "maxLength": 64,
        "pattern": "^[A-Za-z0-9._-]+$"
      },
      "RevalidationMarker": {
        "description": "Opaque. Identifies the exact published version a response reflects.",
        "type": "string",
        "pattern": "^m1\\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"
      },
      "ClauseAnchor": {
        "type": "string",
        "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}:[A-Za-z0-9._-]{1,64}$"
      },
      "Notice": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "statement",
          "disputeRoute"
        ],
        "properties": {
          "statement": {
            "type": "string",
            "minLength": 1
          },
          "disputeRoute": {
            "type": "string",
            "minLength": 1
          }
        }
      },
      "Receipt": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "receiptId",
          "sourceAuthority",
          "jurisdiction",
          "sourceVersionId",
          "sourceVersionLabel",
          "originalSha256",
          "clauseAnchor",
          "publicationDecisionId",
          "publishedAt",
          "receiptStatus"
        ],
        "properties": {
          "receiptId": {
            "type": "string",
            "format": "uuid"
          },
          "sourceAuthority": {
            "type": "string",
            "minLength": 1
          },
          "jurisdiction": {
            "type": "string",
            "minLength": 1
          },
          "sourceVersionId": {
            "type": "string",
            "format": "uuid"
          },
          "sourceVersionLabel": {
            "type": "string",
            "minLength": 1
          },
          "originalSha256": {
            "type": "string",
            "pattern": "^[0-9a-f]{64}$"
          },
          "clauseAnchor": {
            "$ref": "#/components/schemas/ClauseAnchor"
          },
          "publicationDecisionId": {
            "type": "string",
            "format": "uuid"
          },
          "publishedAt": {
            "type": "string",
            "format": "date-time"
          },
          "receiptStatus": {
            "type": "string",
            "const": "COMPLETE"
          }
        }
      },
      "Clause": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "clauseAnchor",
          "canonicalLabel",
          "clauseText",
          "receipt"
        ],
        "properties": {
          "clauseAnchor": {
            "$ref": "#/components/schemas/ClauseAnchor"
          },
          "canonicalLabel": {
            "type": "string",
            "minLength": 1
          },
          "clauseText": {
            "type": "string",
            "minLength": 1
          },
          "receipt": {
            "$ref": "#/components/schemas/Receipt"
          }
        }
      },
      "PageInfo": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "size",
          "nextCursor"
        ],
        "properties": {
          "size": {
            "type": "integer",
            "minimum": 0
          },
          "nextCursor": {
            "description": "Null when there are no further pages.",
            "type": [
              "string",
              "null"
            ],
            "maxLength": 1024
          }
        }
      },
      "SupportedEvidenceResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "outcome",
          "correlationId",
          "notice",
          "sourceId",
          "revalidationMarker",
          "clauses",
          "page"
        ],
        "properties": {
          "outcome": {
            "type": "string",
            "const": "SUPPORTED_EVIDENCE"
          },
          "correlationId": {
            "$ref": "#/components/schemas/CorrelationId"
          },
          "notice": {
            "$ref": "#/components/schemas/Notice"
          },
          "sourceId": {
            "type": "string",
            "format": "uuid"
          },
          "revalidationMarker": {
            "$ref": "#/components/schemas/RevalidationMarker"
          },
          "clauses": {
            "type": "array",
            "minItems": 1,
            "items": {
              "$ref": "#/components/schemas/Clause"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        }
      },
      "UnchangedResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "outcome",
          "correlationId",
          "notice",
          "revalidationMarker"
        ],
        "properties": {
          "outcome": {
            "type": "string",
            "const": "UNCHANGED"
          },
          "correlationId": {
            "$ref": "#/components/schemas/CorrelationId"
          },
          "notice": {
            "$ref": "#/components/schemas/Notice"
          },
          "revalidationMarker": {
            "$ref": "#/components/schemas/RevalidationMarker"
          }
        }
      },
      "NoSupportedAnswerResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "outcome",
          "correlationId",
          "notice",
          "reason"
        ],
        "properties": {
          "outcome": {
            "type": "string",
            "const": "NO_SUPPORTED_ANSWER"
          },
          "correlationId": {
            "$ref": "#/components/schemas/CorrelationId"
          },
          "notice": {
            "$ref": "#/components/schemas/Notice"
          },
          "reason": {
            "$ref": "#/components/schemas/NoSupportedAnswerReason"
          }
        }
      },
      "CatalogueEntry": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "sourceId",
          "sourceAuthority",
          "jurisdiction",
          "versionLabel",
          "status",
          "hasSupportedEvidence",
          "clauseCount",
          "revalidationMarker"
        ],
        "properties": {
          "sourceId": {
            "type": "string",
            "format": "uuid"
          },
          "sourceAuthority": {
            "type": "string",
            "minLength": 1
          },
          "jurisdiction": {
            "type": "string",
            "minLength": 1
          },
          "versionLabel": {
            "description": "Null when the source has no published version.",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "$ref": "#/components/schemas/CatalogueStatus"
          },
          "hasSupportedEvidence": {
            "type": "boolean"
          },
          "clauseCount": {
            "description": "Null when the source has no supported evidence.",
            "type": [
              "integer",
              "null"
            ],
            "minimum": 0
          },
          "revalidationMarker": {
            "description": "Null when the source has no supported evidence.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/RevalidationMarker"
              },
              {
                "type": "null"
              }
            ]
          }
        }
      },
      "CatalogueResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "outcome",
          "correlationId",
          "notice",
          "entries",
          "page"
        ],
        "properties": {
          "outcome": {
            "type": "string",
            "const": "CATALOGUE"
          },
          "correlationId": {
            "$ref": "#/components/schemas/CorrelationId"
          },
          "notice": {
            "$ref": "#/components/schemas/Notice"
          },
          "entries": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CatalogueEntry"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        }
      },
      "ClauseIndexEntry": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "clauseAnchor",
          "canonicalLabel"
        ],
        "properties": {
          "clauseAnchor": {
            "$ref": "#/components/schemas/ClauseAnchor"
          },
          "canonicalLabel": {
            "type": "string",
            "minLength": 1
          }
        }
      },
      "ClauseIndexResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "outcome",
          "correlationId",
          "notice",
          "sourceId",
          "revalidationMarker",
          "anchors",
          "page"
        ],
        "properties": {
          "outcome": {
            "type": "string",
            "const": "CLAUSE_INDEX"
          },
          "correlationId": {
            "$ref": "#/components/schemas/CorrelationId"
          },
          "notice": {
            "$ref": "#/components/schemas/Notice"
          },
          "sourceId": {
            "type": "string",
            "format": "uuid"
          },
          "revalidationMarker": {
            "$ref": "#/components/schemas/RevalidationMarker"
          },
          "anchors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ClauseIndexEntry"
            }
          },
          "page": {
            "$ref": "#/components/schemas/PageInfo"
          }
        }
      },
      "AccessDeniedResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "outcome",
          "correlationId",
          "notice"
        ],
        "properties": {
          "outcome": {
            "type": "string",
            "const": "ACCESS_DENIED"
          },
          "correlationId": {
            "$ref": "#/components/schemas/CorrelationId"
          },
          "notice": {
            "$ref": "#/components/schemas/Notice"
          }
        }
      },
      "UnauthenticatedResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "outcome",
          "correlationId",
          "notice"
        ],
        "properties": {
          "outcome": {
            "type": "string",
            "const": "UNAUTHENTICATED"
          },
          "correlationId": {
            "$ref": "#/components/schemas/CorrelationId"
          },
          "notice": {
            "$ref": "#/components/schemas/Notice"
          }
        }
      },
      "InvalidRequestResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "outcome",
          "correlationId",
          "notice",
          "field"
        ],
        "properties": {
          "outcome": {
            "type": "string",
            "const": "INVALID_REQUEST"
          },
          "correlationId": {
            "$ref": "#/components/schemas/CorrelationId"
          },
          "notice": {
            "$ref": "#/components/schemas/Notice"
          },
          "field": {
            "description": "The name of the malformed field or parameter. Never its value.",
            "type": "string",
            "minLength": 1,
            "maxLength": 64
          }
        }
      },
      "RateLimitedResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "outcome",
          "correlationId",
          "notice",
          "retryAfterSeconds"
        ],
        "properties": {
          "outcome": {
            "type": "string",
            "const": "RATE_LIMITED"
          },
          "correlationId": {
            "$ref": "#/components/schemas/CorrelationId"
          },
          "notice": {
            "$ref": "#/components/schemas/Notice"
          },
          "retryAfterSeconds": {
            "type": "integer",
            "minimum": 1
          }
        }
      },
      "UnavailableResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "outcome",
          "correlationId",
          "notice",
          "retryAfterSeconds"
        ],
        "properties": {
          "outcome": {
            "type": "string",
            "const": "UNAVAILABLE"
          },
          "correlationId": {
            "$ref": "#/components/schemas/CorrelationId"
          },
          "notice": {
            "$ref": "#/components/schemas/Notice"
          },
          "retryAfterSeconds": {
            "type": "integer",
            "minimum": 1
          }
        }
      },
      "HealthResponse": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "status"
        ],
        "properties": {
          "status": {
            "type": "string",
            "enum": [
              "ok",
              "unavailable"
            ]
          }
        }
      },
      "ContractDocument": {
        "description": "This OpenAPI document.",
        "type": "object",
        "required": [
          "openapi",
          "info",
          "paths"
        ],
        "additionalProperties": true
      },
      "RetrievalMetadata": {
        "type": "object",
        "required": [
          "requested",
          "used",
          "scoring",
          "degraded",
          "warnings"
        ],
        "properties": {
          "requested": {
            "enum": [
              "AUTO",
              "WORDS",
              "HYBRID"
            ]
          },
          "used": {
            "enum": [
              "WORDS",
              "EXACT",
              "HYBRID"
            ]
          },
          "scoring": {
            "enum": [
              "word-overlap",
              "identifier",
              "rrf",
              "cross-encoder"
            ]
          },
          "indexVersion": {
            "type": "string"
          },
          "degraded": {
            "type": "boolean"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "Library": {
        "type": "object",
        "properties": {
          "versionId": {
            "type": "string",
            "format": "uuid"
          },
          "digest": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "region": {
            "type": "string"
          },
          "pages": {
            "type": "integer"
          },
          "counts": {
            "type": "object",
            "additionalProperties": {
              "type": "integer"
            }
          }
        }
      },
      "Refusal": {
        "type": "object",
        "required": [
          "outcome",
          "correlationId"
        ],
        "properties": {
          "outcome": {
            "enum": [
              "UNAUTHENTICATED",
              "ACCESS_DENIED",
              "NOT_ENTITLED",
              "NOT_REGISTERED",
              "INVALID_REQUEST",
              "RATE_LIMITED",
              "UNAVAILABLE"
            ]
          },
          "correlationId": {
            "type": "string"
          },
          "code": {
            "enum": [
              "BUSY",
              "TIMEOUT",
              "INDEX_UNAVAILABLE"
            ]
          }
        }
      }
    }
  }
}
