openapi: 3.1.0
info:
  title: TrustedListOfTrustedLists.org
  version: 1.0.0
  summary: The meta-list — recognised trust frameworks, resolvable via Meta-List Profile tokens and TRQP v2.0.
  description: |
    Read-only trust registry publishing recognition statements about trust frameworks. Level-1 issuer data is
    proxied (iSHARE), mirrored (GLEIF) or referenced (eIDAS LOTL, Ayra-recognised registries) — upstream authority
    is always preserved. Wording rule: the meta-list is an *authority among peers*, never a "root of trust".
  license: { name: Apache-2.0, url: 'https://www.apache.org/licenses/LICENSE-2.0' }
servers:
  - url: https://trustedlistoftrustedlists.org
tags:
  - { name: meta-list }
  - { name: frameworks }
  - { name: trqp, description: "ToIP Trust Registry Query Protocol v2.0 binding" }
  - { name: discovery }
paths:
  /trusted_list:
    get:
      tags: [meta-list]
      operationId: getMetaList
      summary: Recognised trust frameworks (level 2)
      parameters:
        - { name: format, in: query, schema: { type: string, enum: [jwt, json], default: jwt } }
        - { name: status, in: query, schema: { $ref: '#/components/schemas/Status' } }
        - { name: mode, in: query, schema: { type: string, enum: [proxied, mirrored, referenced] } }
        - { name: regulatory, in: query, schema: { type: boolean } }
      responses:
        '200':
          description: Signed meta-list token (payload per schemas/signed-token.schema.json with listType recognisedFrameworks)
          content:
            application/vnd.metalist+jwt: { schema: { type: string } }
            application/json: { schema: { $ref: '#/components/schemas/MetaListPayload' } }  # unsigned view, X-Unsigned-View: true
  /trusted_list.xml:
    get:
      tags: [meta-list]
      operationId: getMetaListXml
      summary: ETSI TS 119 612 serialisation with PointersToOtherTSL per framework (phase 2)
      responses:
        '200': { description: XML, content: { application/xml: { schema: { type: string } } } }
        '501': { $ref: '#/components/responses/Problem' }
  /parties:
    get:
      tags: [frameworks]
      operationId: getFrameworkParties
      summary: Level-1 entries of one framework (issuers; for eu-lotl the referenced national lists)
      parameters:
        - { name: framework, in: query, required: true, schema: { type: string }, example: ishare }
        - { name: format, in: query, schema: { type: string, enum: [jwt, json], default: jwt } }
        - { name: status, in: query, schema: { $ref: '#/components/schemas/Status' } }
        - { name: role, in: query, schema: { type: string } }
        - { name: credentialType, in: query, schema: { type: string, format: uri } }
        - { name: page, in: query, schema: { type: integer, minimum: 1, default: 1 } }
        - { name: pageSize, in: query, schema: { type: integer, minimum: 1, maximum: 100, default: 50 } }
      responses:
        '200':
          description: Signed token; entries per schemas/issuer-entry.schema.json; `source` in {live, snapshot, mirror, reference}
          headers:
            Warning: { schema: { type: string }, description: "110 when served from snapshot" }
          content:
            application/vnd.metalist+jwt: { schema: { type: string } }
            application/json: { schema: { type: object } }
        '400': { $ref: '#/components/responses/Problem' }
        '404': { $ref: '#/components/responses/Problem' }
  /frameworks/{id}:
    get:
      tags: [frameworks]
      operationId: getFramework
      summary: Single framework entry with adapter status
      parameters: [{ name: id, in: path, required: true, schema: { type: string } }]
      responses:
        '200':
          description: Framework entry + adapter status
          content:
            application/json:
              schema:
                type: object
                properties:
                  entry: { $ref: '#/components/schemas/FrameworkEntry' }
                  adapter:
                    type: object
                    properties:
                      mode: { type: string, enum: [proxied, mirrored, referenced] }
                      lastRefreshed: { type: string, format: date-time }
                      source: { type: string, enum: [live, snapshot, mirror, reference] }
                      snapshotAgeSeconds: { type: integer }
                      upstreamHealthy: { type: boolean }
        '404': { $ref: '#/components/responses/Problem' }
  /recognition:
    post:
      tags: [trqp]
      operationId: trqpRecognition
      summary: "TRQP recognition: does authority_id recognise entity_id (as authoritative for action on resource)?"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/TrqpRequest' }
            example: { authority_id: "did:web:trustedlistoftrustedlists.org", entity_id: "did:web:trustedlist.ishare.eu", action: "issue", resource: "https://schemas.ishare.eu/data-rights-credential" }
      responses:
        '200':
          description: Recognition answer
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TrqpRecognitionResponse' }
        '400': { $ref: '#/components/responses/Problem' }
        '404': { $ref: '#/components/responses/Problem' }
  /authorization:
    post:
      tags: [trqp]
      operationId: trqpAuthorization
      summary: "TRQP authorization: does authority_id (a framework) authorise entity_id (an issuer) to take action on resource?"
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/TrqpRequest' }
            example: { authority_id: "did:web:trustedlist.ishare.eu", entity_id: "EU.EORI.NL000000001", action: "issue", resource: "https://schemas.ishare.eu/participant-credential" }
      responses:
        '200':
          description: Authorization answer with two-hop evidence (framework entry + meta-list recognition)
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TrqpAuthorizationResponse' }
        '400': { $ref: '#/components/responses/Problem' }
        '404': { $ref: '#/components/responses/Problem' }
        '501': { $ref: '#/components/responses/Problem' }
  /capabilities:
    get: { tags: [discovery], operationId: getCapabilities, summary: Profile capabilities of this authority, responses: { '200': { description: "Signed capabilities token incl. trqp endpoints and frameworks list" } } }
  /.well-known/did.json:
    get: { tags: [discovery], operationId: getDid, summary: DID document of the meta-list authority, responses: { '200': { description: "did:web:trustedlistoftrustedlists.org" } } }
  /jwks:
    get: { tags: [discovery], operationId: getJwks, summary: Current and previous signing keys, responses: { '200': { description: JWK Set } } }
  /governance/:
    get: { tags: [discovery], operationId: getGovernance, summary: Ecosystem governance framework primary document, responses: { '200': { description: EGF primary document (ToIP Governance Metamodel structure) } } }
  /openapi.json:
    get: { tags: [discovery], operationId: getOpenApi, summary: This OpenAPI document, responses: { '200': { description: This document } } }
  /health:
    get: { tags: [discovery], operationId: health, summary: Liveness probe, responses: { '200': { description: Alive } } }
  /ready:
    get: { tags: [discovery], operationId: ready, summary: Readiness probe with per-adapter freshness, responses: { '200': { description: Per-adapter freshness and health } } }
components:
  responses:
    Problem:
      description: RFC 7807 problem
      content:
        application/problem+json:
          schema:
            type: object
            properties:
              type: { type: string, format: uri, example: https://trustedlistoftrustedlists.org/problems/unknown-framework }
              title: { type: string }
              status: { type: integer }
              detail: { type: string }
              instance: { type: string }
  schemas:
    Status:
      type: string
      enum: [granted, undersupervision, "supervision ceased", suspended, withdrawn]
    Identifier:
      type: object
      required: [scheme, value]
      properties:
        scheme: { type: string, enum: [did, eori, lei, aid, url, x509-subject] }
        value: { type: string }
    FrameworkEntry:
      $ref: '#/components/schemas/FrameworkEntryInline'
    FrameworkEntryInline:
      description: See schemas/framework-entry.schema.json (authoritative)
      type: object
      required: [id, name, authority, egfReference, listLocation, anchoringStyle, mode, status]
      properties:
        id: { type: string }
        name: { type: string }
        authority:
          type: object
          properties:
            name: { type: string }
            identifiers: { type: array, items: { $ref: '#/components/schemas/Identifier' } }
        egfReference: { type: string, format: uri }
        listLocation: { type: string, format: uri }
        issuersLocation: { type: string, format: uri }
        trqpEndpoint: { type: [string, "null"], format: uri }
        anchoringStyle: { type: string, enum: [list, chain] }
        mode: { type: string, enum: [proxied, mirrored, referenced] }
        scope: { type: array, items: { type: string } }
        status: { $ref: '#/components/schemas/Status' }
        statusSince: { type: string, format: date }
        assuranceLevel: { type: string }
        regulatory: { type: boolean, default: false }
    MetaListPayload:
      type: object
      properties:
        iss: { type: string }
        listType: { type: string, enum: [recognisedFrameworks] }
        listVersion: { type: integer }
        nextUpdate: { type: string, format: date-time }
        entries: { type: array, items: { $ref: '#/components/schemas/FrameworkEntryInline' } }
    TrqpRequest:
      type: object
      required: [entity_id, authority_id]
      properties:
        entity_id: { type: string }
        authority_id: { type: string }
        action: { type: string }
        resource: { type: string }
        time: { type: string, format: date-time, description: Evaluate as of this time (defaults to now) }
    TrqpEvidence:
      type: object
      properties:
        listType: { type: string }
        listVersion: { type: integer }
        entryId: { type: string }
        tokenJti: { type: string }
        source: { type: string, enum: [live, snapshot, mirror, reference, upstream-trqp] }
    TrqpRecognitionResponse:
      type: object
      required: [recognized]
      properties:
        recognized: { type: boolean }
        status: { $ref: '#/components/schemas/Status' }
        evidence: { $ref: '#/components/schemas/TrqpEvidence' }
        message: { type: string }
        evaluated_at: { type: string, format: date-time }
    TrqpAuthorizationResponse:
      type: object
      required: [authorized]
      properties:
        authorized: { type: boolean }
        status: { $ref: '#/components/schemas/Status' }
        evidence:
          type: object
          properties:
            framework: { $ref: '#/components/schemas/TrqpEvidence' }
            recognition: { $ref: '#/components/schemas/TrqpEvidence' }
        message: { type: string, example: "iSHARE accredited EU.EORI.NL000000001 as participantCredentialIssuer; the meta-list recognises iSHARE for this credential type." }
        evaluated_at: { type: string, format: date-time }
