openapi: 3.0.3
info:
  title: Open Energy Platform API
  version: v0
  description: OpenAPI schema for the Open Energy Platform REST API.
paths:
  /api/v0/advanced/connection/close:
    post:
      operationId: advanced_connection_close_create
      description: |-
        Runs `close_raw_connection` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Connection'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `close_raw_connection`, under `content`.
  /api/v0/advanced/connection/close_all:
    get:
      operationId: advanced_connection_close_all_retrieve
      description: |-
        Closes all of this account's open database connections. The way out of a session left open by a client that stopped without closing it.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      summary: Close every connection this account holds
      tags:
      - 'Advanced: Connection'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Closed.
  /api/v0/advanced/connection/commit:
    post:
      operationId: advanced_connection_commit_create
      description: |-
        Runs `commit_raw_connection` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Connection'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `commit_raw_connection`, under `content`.
  /api/v0/advanced/connection/open:
    post:
      operationId: advanced_connection_open_create
      description: |-
        Runs `open_raw_connection` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Connection'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `open_raw_connection`, under `content`.
  /api/v0/advanced/connection/rollback:
    post:
      operationId: advanced_connection_rollback_create
      description: |-
        Runs `rollback_raw_connection` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Connection'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `rollback_raw_connection`, under `content`.
  /api/v0/advanced/cursor/close:
    post:
      operationId: advanced_cursor_close_create
      description: |-
        Runs `close_cursor` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Cursor'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `close_cursor`, under `content`.
  /api/v0/advanced/cursor/fetch_all:
    post:
      operationId: advanced_cursor_fetch_all_create
      description: |-
        Streams rows from a cursor opened by `advanced/cursor/open`, one JSON array per line rather than one document -- so a large result can be read without holding it whole.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      summary: Fetch rows from an open cursor
      tags:
      - 'Advanced: Cursor'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: One row per line, each a JSON array of cell values in column
            order.
  /api/v0/advanced/cursor/fetch_many:
    post:
      operationId: advanced_cursor_fetch_many_create
      description: |-
        Streams rows from a cursor opened by `advanced/cursor/open`, one JSON array per line rather than one document -- so a large result can be read without holding it whole.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      summary: Fetch rows from an open cursor
      tags:
      - 'Advanced: Cursor'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: One row per line, each a JSON array of cell values in column
            order.
  /api/v0/advanced/cursor/fetch_one:
    post:
      operationId: advanced_cursor_fetch_one_create
      description: |-
        Runs `fetchone` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Cursor'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `fetchone`, under `content`.
  /api/v0/advanced/cursor/open:
    post:
      operationId: advanced_cursor_open_create
      description: |-
        Runs `open_cursor` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Cursor'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `open_cursor`, under `content`.
  /api/v0/advanced/delete:
    post:
      operationId: advanced_delete_create
      description: |-
        Runs `data_delete` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `data_delete`, under `content`.
  /api/v0/advanced/do_begin_twophase:
    post:
      operationId: advanced_do_begin_twophase_create
      description: |-
        Runs `do_begin_twophase` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Two phase'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `do_begin_twophase`, under `content`.
  /api/v0/advanced/do_commit_twophase:
    post:
      operationId: advanced_do_commit_twophase_create
      description: |-
        Runs `do_commit_twophase` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Two phase'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `do_commit_twophase`, under `content`.
  /api/v0/advanced/do_prepare_twophase:
    post:
      operationId: advanced_do_prepare_twophase_create
      description: |-
        Runs `do_prepare_twophase` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Two phase'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `do_prepare_twophase`, under `content`.
  /api/v0/advanced/do_recover_twophase:
    post:
      operationId: advanced_do_recover_twophase_create
      description: |-
        Runs `do_recover_twophase` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Two phase'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `do_recover_twophase`, under `content`.
  /api/v0/advanced/do_rollback_twophase:
    post:
      operationId: advanced_do_rollback_twophase_create
      description: |-
        Runs `do_rollback_twophase` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - 'Advanced: Two phase'
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `do_rollback_twophase`, under `content`.
  /api/v0/advanced/get_columns:
    post:
      operationId: advanced_get_columns_create
      description: |-
        Runs `get_columns` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `get_columns`, under `content`.
  /api/v0/advanced/get_foreign_keys:
    post:
      operationId: advanced_get_foreign_keys_create
      description: |-
        Runs `get_foreign_keys` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `get_foreign_keys`, under `content`.
  /api/v0/advanced/get_indexes:
    post:
      operationId: advanced_get_indexes_create
      description: |-
        Runs `get_indexes` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `get_indexes`, under `content`.
  /api/v0/advanced/get_isolation_level:
    post:
      operationId: advanced_get_isolation_level_create
      description: |-
        Runs `get_isolation_level` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `get_isolation_level`, under `content`.
  /api/v0/advanced/get_pk_constraint:
    post:
      operationId: advanced_get_pk_constraint_create
      description: |-
        Runs `get_pk_constraint` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `get_pk_constraint`, under `content`.
  /api/v0/advanced/get_schema_names:
    post:
      operationId: advanced_get_schema_names_create
      description: |-
        Runs `get_schema_names` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `get_schema_names`, under `content`.
  /api/v0/advanced/get_table_names:
    post:
      operationId: advanced_get_table_names_create
      description: |-
        Runs `get_table_names` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `get_table_names`, under `content`.
  /api/v0/advanced/get_unique_constraints:
    post:
      operationId: advanced_get_unique_constraints_create
      description: |-
        Runs `get_unique_constraints` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `get_unique_constraints`, under `content`.
  /api/v0/advanced/get_view_definition:
    post:
      operationId: advanced_get_view_definition_create
      description: |-
        Runs `get_view_definition` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `get_view_definition`, under `content`.
  /api/v0/advanced/get_view_names:
    post:
      operationId: advanced_get_view_names_create
      description: |-
        Runs `get_view_names` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `get_view_names`, under `content`.
  /api/v0/advanced/has_schema:
    post:
      operationId: advanced_has_schema_create
      description: |-
        Runs `has_schema` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `has_schema`, under `content`.
  /api/v0/advanced/has_table:
    post:
      operationId: advanced_has_table_create
      description: |-
        Runs `has_table` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `has_table`, under `content`.
  /api/v0/advanced/insert:
    post:
      operationId: advanced_insert_create
      description: |-
        Runs `data_insert` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `data_insert`, under `content`.
  /api/v0/advanced/search:
    post:
      operationId: advanced_search_create
      description: |-
        Runs `data_search` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `data_search`, under `content`.
  /api/v0/advanced/set_isolation_level:
    post:
      operationId: advanced_set_isolation_level_create
      description: |-
        Runs `set_isolation_level` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `set_isolation_level`, under `content`.
  /api/v0/advanced/update:
    post:
      operationId: advanced_update_create
      description: |-
        Runs `data_update` against the OEDB.

        Part of the **advanced** interface: a thin, authenticated passthrough to the database that exists to be driven by a client library rather than by hand. A call carrying no `connection_id` runs and commits on its own; one carrying the pair from `connection/open` and `cursor/open` joins that transaction, which is what lets several calls be committed or rolled back together.
      tags:
      - Advanced
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/AdvancedRequest'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdvancedResponse'
          description: The result of `data_update`, under `content`.
  /api/v0/datasets/:
    get:
      operationId: datasets_list
      description: Every dataset on the platform, each with its metadata. The `resources`
        of a dataset are assembled from its member tables at read time rather than
        stored, so this never reports a resource the dataset no longer holds. Public.
      summary: List datasets
      tags:
      - datasets
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/DatasetRead'
          description: ''
    post:
      operationId: datasets_create
      description: Creates a new dataset.
      summary: Create dataset
      tags:
      - datasets
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DatasetCreate'
            examples:
              DatasetExample:
                value:
                  name: test_dataset
                  title: Wind Power Dataset Germany
                  description: Contains hourly wind generation data for Germany.
                  at_id: https://example.org/datasets/test_dataset
                summary: Example request body for creating a dataset
                description: Use this JSON object to create a new dataset. The `at_id`
                  field is optional and can contain a persistent identifier.
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/DatasetCreate'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/DatasetCreate'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '201':
          description: Dataset created
        '400':
          description: The payload was rejected.
  /api/v0/datasets/{dataset_name}/:
    get:
      operationId: datasets_retrieve
      description: Returns metadata for a single dataset.
      summary: Get dataset
      parameters:
      - in: path
        name: dataset_name
        schema:
          type: string
        required: true
      tags:
      - datasets
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DatasetRead'
          description: ''
    put:
      operationId: datasets_update
      description: Updates metadata for an existing dataset.
      summary: Update dataset
      parameters:
      - in: path
        name: dataset_name
        schema:
          type: string
        required: true
      tags:
      - datasets
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DatasetCreate'
            examples:
              UpdateDatasetExample:
                value:
                  name: test_dataset
                  title: Updated Wind Power Dataset Germany
                  description: Updated description with more details.
                  at_id: https://example.org/datasets/test_dataset
                summary: Example request body for updating a dataset
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/DatasetCreate'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/DatasetCreate'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '200':
          description: Dataset updated
    delete:
      operationId: datasets_destroy
      description: Deletes the specified dataset.
      summary: Delete dataset
      parameters:
      - in: path
        name: dataset_name
        schema:
          type: string
        required: true
      tags:
      - datasets
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '204':
          description: Dataset deleted
  /api/v0/datasets/{dataset_name}/assign-tables/:
    post:
      operationId: datasets_assign_tables_create
      description: Assigns existing OEP tables to an existing dataset. The dataset
        must already exist and the referenced tables must already exist. After assignment,
        the dataset resources are updated from the table metadata.
      summary: Assign tables to dataset
      parameters:
      - in: path
        name: dataset_name
        schema:
          type: string
        description: 'Name of the dataset to which the tables should be assigned.
          Example: `test_dataset`.'
        required: true
      tags:
      - datasets
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DatasetAssignTables'
            examples:
              AssignTablesExample:
                value:
                  tables:
                  - name: germany_wind_hourly
                  - name: germany_wind_daily
                summary: Example request body for assigning tables
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/DatasetAssignTables'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/DatasetAssignTables'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '200':
          description: Tables were assigned to the dataset.
        '404':
          description: Dataset was not found.
  /api/v0/datasets/{dataset_name}/resources/:
    get:
      operationId: datasets_resources_list
      description: Returns the tables/resources that belong to a dataset.
      summary: List dataset resources
      parameters:
      - in: path
        name: dataset_name
        schema:
          type: string
        required: true
      tags:
      - datasets
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/DatasetResource'
          description: ''
  /api/v0/datasets/{dataset_name}/unassign-tables/:
    post:
      operationId: datasets_unassign_tables_create
      description: Removes the named tables from the dataset. The tables are not deleted
        -- a dataset is a catalogue entry, and leaving it is not leaving the platform.
        A name the dataset does not hold is reported in `missing` rather than refused,
        so a repeated call is safe.
      summary: Unassign tables from a dataset
      parameters:
      - in: path
        name: dataset_name
        schema:
          type: string
        description: The dataset's name.
        required: true
      tags:
      - datasets
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DatasetAssignTables'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/DatasetAssignTables'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/DatasetAssignTables'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`removed` names what was detached and `missing` what the dataset
            did not hold.'
  /api/v0/datasets/list_all/scenario/:
    get:
      operationId: datasets_list_all_scenario_list
      description: |-
        Used for the scenario bundles react app to be able to populate
        form select options with existing datasets from scenario topic.
      tags:
      - datasets
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ScenarioDataTables'
          description: ''
  /api/v0/db/table-sizes/:
    get:
      operationId: db_table_sizes_retrieve
      description: How much space tables take in the database. Without `table` this
        lists every table; with one it describes that table in detail.
      summary: Table sizes
      parameters:
      - in: query
        name: table
        schema:
          type: string
        description: One table's name. Omit it for the whole list.
      tags:
      - db
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The sizes.
  /api/v0/factsheet/frameworks/:
    get:
      operationId: factsheet_frameworks_list
      description: |-
        Used for the scenario bundles react app to be able to select a existing
        framework or model factsheet.
      tags:
      - factsheet
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Energyframework'
          description: ''
  /api/v0/factsheet/models/:
    get:
      operationId: factsheet_models_list
      description: |-
        Used for the scenario bundles react app to be able to select a existing
        framework or model factsheet.
      tags:
      - factsheet
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '200':
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Energymodel'
          description: ''
  /api/v0/oekg/sparql/:
    post:
      operationId: oekg_sparql_create
      description: |-
        Hands a query to the graph store and returns what comes back. **Reads only**: a query that would update or delete is refused whatever the caller's permissions, so this is not a way to write to the graph. The scenario-bundle endpoints are, and they validate what they write against the OEKG shape.

        Authenticated by token. A `format` other than `json` is returned with the store's own content type rather than parsed.
      summary: Query the OEKG with SPARQL
      tags:
      - oekg
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Sparql'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Sparql'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Sparql'
        required: true
      security:
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The store's answer, in the format asked for.
  /api/v0/scenario-bundle/scenario/manage-datasets/:
    post:
      operationId: scenario_bundle_scenario_manage_datasets_create
      description: '**Superseded** by the scenario-bundle dataset-link endpoints under
        `/api/v0/scenario-bundles/<uid>/scenarios/<sid>/datasets/`, which validate
        what they write against the OEKG shape and say on every read whether a citation
        still resolves. This route writes predicates the canonical shape does not
        validate; it is kept because the user interface calls it.'
      summary: Attach datasets to a scenario (superseded)
      tags:
      - scenario-bundle
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScenarioBundleScenarioDataset'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/ScenarioBundleScenarioDataset'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/ScenarioBundleScenarioDataset'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: What was attached.
  /api/v0/scenario-bundles/:
    get:
      operationId: scenario_bundles_list
      description: |-
        A page of summaries: identifier, acronym, label, version and counts.

        Not bundles. A listing that returned whole bundles would carry every
        client the whole corpus, and would drag the relational resolution a
        dataset link needs across every link of every bundle on a public
        endpoint -- which is how the two listings next door on this platform
        became unusable.

        `?acronym=` is the filter the contract depends on: it is how a pipeline
        holding no state between runs finds its own bundle again, and the
        `_meta` it gets back carries the version its next write must send.

        **Public.** No authentication is required, and sending credentials changes nothing about the answer. The OEKG SPARQL endpoint already serves the same data, so a token here would protect nothing while making published research records awkward to read. (The reference page draws a **closed** padlock here. It marks a security requirement the reader already meets, not a protected endpoint -- on that page the closed padlock is the public one.)
      parameters:
      - in: query
        name: acronym
        schema:
          type: string
        description: 'Only the bundle carrying exactly this acronym. **The filter
          the contract depends on**: it is how a pipeline holding no state between
          runs finds its own bundle again, and the `_meta` it gets back carries the
          version its next write has to send.'
      - in: query
        name: author
        schema:
          type: string
        description: The IRI of an author of one of a bundle's study reports. Repeating
          this parameter widens it; different parameters narrow each other, which
          is what a faceted interface means by ticking two boxes in one facet.
      - in: query
        name: descriptor
        schema:
          type: string
        description: The IRI of a descriptor a bundle is tagged with. Repeating this
          parameter widens it; different parameters narrow each other, which is what
          a faceted interface means by ticking two boxes in one facet.
      - in: query
        name: funder
        schema:
          type: string
        description: The IRI of a funder a bundle names. Repeating this parameter
          widens it; different parameters narrow each other, which is what a faceted
          interface means by ticking two boxes in one facet.
      - in: query
        name: organisation
        schema:
          type: string
        description: The IRI of an organisation a bundle names. Repeating this parameter
          widens it; different parameters narrow each other, which is what a faceted
          interface means by ticking two boxes in one facet.
      - in: query
        name: page
        schema:
          type: integer
        description: Which page of the result to return. 1-based.
      - in: query
        name: page_size
        schema:
          type: integer
        description: 'How many entries a page holds. Defaults to 25 and is capped
          at 100: this endpoint is public, and no public collection here has an unbounded
          mode.'
      - in: query
        name: published_from
        schema:
          type: integer
        description: Bundles with a study report published in this year or later.
          Either end of the range may be given alone.
      - in: query
        name: published_to
        schema:
          type: integer
        description: Bundles with a study report published in this year or earlier.
          Either end of the range may be given alone.
      - in: query
        name: year_from
        schema:
          type: integer
        description: Bundles with a scenario year at or after this. Either end of
          the range may be given alone.
      - in: query
        name: year_to
        schema:
          type: integer
        description: Bundles with a scenario year at or before this. Either end of
          the range may be given alone.
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScenarioBundleSummaryPage'
          description: 'A page of summaries. Each carries the two fields a human recognises
            a bundle by at the top level -- `label` and `acronym` -- and everything
            a client cannot write in `_meta`: the identifier, the version, and the
            number of scenarios and study reports the bundle holds.'
    post:
      operationId: scenario_bundles_create
      description: |-
        Create a whole scenario bundle, its scenarios and study reports with it.

        Nothing is written until the payload has been checked for structure,
        the acronym for uniqueness and the assembled **post-state** against the
        OEKG shape -- so an invalid payload leaves the graph untouched, not
        mostly untouched. The write itself is one request, which the store
        makes one transaction, and the acronym check is bound inside it: two
        concurrent creates cannot both take an acronym they both found free.

        **The server mints the identifier.** A client sends none anywhere in
        this API, and `uid` is a rejected key rather than an ignored one. A
        pipeline that keeps no state re-identifies its bundle afterwards with
        `GET /api/v0/scenario-bundles/?acronym=...`.

        Nested `scenarios` and `study_reports` are accepted here and **only**
        here: a `PATCH` refuses them, so no single call can drop a bundle's
        parts by omitting them. Dataset links are not accepted -- they hang off
        a scenario and have their own endpoint.

        Unlike every other write, a create is judged strictly: there is no
        pre-state, so there is nothing it can have inherited and every
        violation of the shape is its own.

        **Requires authentication.** Any authenticated account may create a scenario bundle, and the account that creates one becomes its owner, which is what lets it write to the bundle afterwards. (The reference page draws an **open** padlock here. It marks a security requirement not yet met -- use *Authorize* -- not an unprotected endpoint.)
      tags:
      - scenario-bundles
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScenarioBundleCreate'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/ScenarioBundleCreate'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/ScenarioBundleCreate'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not recognise.
            Reads here need none; writes do.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Another bundle already has this acronym, so nothing was written.
            The acronym is how a stateless pipeline finds its own bundle again, so
            two bundles sharing one is not untidy: it is a pipeline writing into a
            stranger''s record.'
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '201':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
            Location:
              schema:
                type: string
              description: 'Where the created resource can be read. The identifier
                in it was minted by the server: this API accepts none from a client.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScenarioBundleRead'
          description: Created. The body is the bundle as it now stands -- exactly
            what a write accepts, plus `_meta`. `Location` names its URL and `ETag`
            the version the next write has to send back.
  /api/v0/scenario-bundles/{uid}/:
    get:
      operationId: scenario_bundles_retrieve
      description: |-
        Read one bundle, publicly.

        Dataset links are **not** in this body: they hang off a scenario and
        are read at their own endpoint.

        **Public.** No authentication is required, and sending credentials changes nothing about the answer. The OEKG SPARQL endpoint already serves the same data, so a token here would protect nothing while making published research records awkward to read. (The reference page draws a **closed** padlock here. It marks a security requirement the reader already meets, not a protected endpoint -- on that page the closed padlock is the public one.)
      parameters:
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: query
        name: format
        schema:
          type: string
          enum:
          - json
          - json-ld
          - turtle
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScenarioBundleRead'
            text/turtle:
              schema:
                $ref: '#/components/schemas/ScenarioBundleRead'
            application/ld+json:
              schema:
                $ref: '#/components/schemas/ScenarioBundleRead'
          description: 'The bundle: exactly what a write accepts, plus `_meta`, with
            its scenarios and study reports nested so that a client can send back
            what it read without stripping anything. `ETag` carries the version the
            next write has to send. On `Accept: text/turtle` or `application/ld+json`
            the same bundle comes back as its stored subgraph instead; `expand` has
            nothing to do there, because triples are already what they are.'
    patch:
      operationId: scenario_bundles_partial_update
      description: |-
        Change the fields this payload names, and no others.

        A key the payload does not mention is **genuinely untouched** -- not
        read and written back -- which is also what stops an unrelated patch
        from re-minting every framework and model in the bundle. An empty list
        is how a multi-valued key is cleared, which is why omission cannot
        mean the same thing.

        Sub-resources are not accepted here, though a read nests them: a
        `PATCH` is partial by nature and nobody sends a whole read to one, so
        accepting `scenarios` would give a single call the power to drop a
        bundle's parts by omitting them. They have their own endpoints.

        A rename answers for the acronym's uniqueness the same way a create
        does, and for the same reason. A shared node -- a contact, an
        organisation, a funder, a region -- may be referenced by `iri` but
        never renamed: other bundles cite it, and one payload may not rewrite
        their labels.

        **This write is judged by what it introduces.** Most bundles in the
        graph were written by the browser and do not conform to the shape; a
        violation this payload did not add is not this caller's to answer for,
        and `pre_existing_violations` reports how many were found. Refusing
        them would make the missing fields -- which are what a human would add
        by patching -- unfixable through this API.

        **Requires authentication**, and only an owner of this scenario bundle may write to it -- a bundle with no recorded owner can be changed by an administrator only. Ownership is the bundle's, whatever part of it this operation names. (The reference page draws an **open** padlock here. It marks a security requirement not yet met -- use *Authorize* -- not an unprotected endpoint.)
      parameters:
      - in: header
        name: If-Match
        schema:
          type: string
        description: 'The entity tag of the bundle state this write applies to, as
          returned in `ETag` by the read it was built from. **Required, with no opt-out**:
          without it a client that has never heard of the header would overwrite a
          change made since it read, and neither party would be told. `*` is refused
          as an absent header rather than honoured as a wildcard, because it satisfies
          the letter of the precondition while withholding the one thing the precondition
          is for. A weak validator (`W/"4"`) and a bare number are both read as the
          version they plainly name.'
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchedScenarioBundle'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/PatchedScenarioBundle'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/PatchedScenarioBundle'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not recognise.
            Reads here need none; writes do.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Authenticated, but not an owner of this scenario bundle. A
            bundle with no recorded owner is administrator-only.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Either the bundle moved between the read this write was prepared
            from and the write itself, or -- on a rename -- another bundle took the
            acronym. The guard carries both conditions, so this refusal names neither;
            the advice is the same for both. Nothing was written.
        '412':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` named a version, and it is not the current one.
            Nothing was written. The response says which version the bundle is at.'
        '428':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` was absent, so this write did not say which version
            it was editing and nothing was written. The response names the current
            entity tag to send.'
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScenarioBundleRead'
          description: Changed. The body is the bundle as it now stands and `ETag`
            is its new version -- so a pipeline chains writes without reading again.
    delete:
      operationId: scenario_bundles_destroy
      description: |-
        Delete this bundle, in the second of two steps.

        The first step is the read a client needs anyway: it returns the
        version to guard on and the acronym to retype. This step requires both,
        and they defend different accidents -- the version catches a bundle
        that changed since it was read, the acronym catches the wrong bundle
        entirely, which is the realistic failure for a pipeline looping over
        identifiers and the one a version cannot see.

        **The order of the refusals is the contract**, not an implementation
        detail: existence, then ownership, then the version, then the
        confirmation. A repeated delete therefore answers `404`, and a client
        may treat that as success. Answering `204` to it instead would swallow
        the wrong-identifier delete -- a bundle that is gone has no acronym
        left to check a confirmation against, so a blanket success would
        confirm anything.

        `200` with a body rather than `204`, as for a part: the typed
        containment walk can decide that a node another bundle still cites is
        unlinked rather than deleted, and no status code can say that.

        **Requires authentication**, and only an owner of this scenario bundle may write to it -- a bundle with no recorded owner can be changed by an administrator only. Ownership is the bundle's, whatever part of it this operation names. (The reference page draws an **open** padlock here. It marks a security requirement not yet met -- use *Authorize* -- not an unprotected endpoint.)
      parameters:
      - in: header
        name: If-Match
        schema:
          type: string
        description: 'The entity tag of the bundle state this write applies to, as
          returned in `ETag` by the read it was built from. **Required, with no opt-out**:
          without it a client that has never heard of the header would overwrite a
          change made since it read, and neither party would be told. `*` is refused
          as an absent header rather than honoured as a wildcard, because it satisfies
          the letter of the precondition while withholding the one thing the precondition
          is for. A weak validator (`W/"4"`) and a bare number are both read as the
          version they plainly name.'
        required: true
      - in: query
        name: confirm
        schema:
          type: string
        description: 'The bundle''s acronym, retyped. It guards the accident the version
          cannot: right verb, wrong identifier. Compared **exactly** -- normalising
          it away would let `api-test` confirm the deletion of `API-TEST`, which is
          the confusion the check exists to catch.'
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The confirmation was missing, or was not this bundle''s acronym,
            so nothing was deleted. `400` rather than `412`: nothing here is a precondition
            on the bundle''s state, and it is exactly as the caller last read it.
            A bundle with no acronym at all cannot be confirmed and so cannot be deleted
            through this API -- give it one with a `PATCH` first.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not recognise.
            Reads here need none; writes do.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Authenticated, but not an owner of this scenario bundle. A
            bundle with no recorded owner is administrator-only.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'No such scenario bundle. A **repeated** delete answers this,
            and a client may treat it as success. `204` instead would swallow the
            wrong-identifier delete: a bundle that is gone has no acronym left to
            check a confirmation against, so a blanket success would confirm anything.'
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The bundle moved between the read this delete was prepared
            from and the delete itself, or something outside it started citing a node
            this delete was about to remove. Nothing was deleted. Read it again, check
            it is still the one you meant, and retry.
        '412':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` named a version, and it is not the current one.
            Nothing was written. The response says which version the bundle is at.'
        '428':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` was absent, so this write did not say which version
            it was editing and nothing was written. The response names the current
            entity tag to send.'
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BundleRemoval'
          description: 'Deleted. The body names what was **deleted** and what was
            only **unlinked**, which no status code can say: a node another bundle
            still cites is kept and detached rather than destroyed. No `ETag`, because
            there is no bundle left to have a version. The bundle''s history survives
            and stays readable at its own URL -- one line saying who removed it, when,
            and under which acronym.'
  /api/v0/scenario-bundles/{uid}/history/:
    get:
      operationId: scenario_bundles_history_list
      description: |-
        Read one bundle's change history.

        **Public, but per bundle and paginated.** What makes a bundle read
        public does not transfer -- that rests on the SPARQL endpoint already
        serving the same data, and this is in no graph. What it exposes is not
        bundle content but who edited what, and when; a per-bundle log is a
        record about a bundle, while a global one would be a profile of a
        person's activity across the platform.

        **A deleted bundle's history is still readable**, and is the whole of
        what a whole-bundle delete leaves: one line saying who removed it, when,
        and under which acronym. So existence here means *in the graph or in
        this ledger*, and a bundle nobody ever wrote has neither.

        Two generations of entry share this endpoint. Rows written before this
        API existed carry `era` saying so, and no field-level summary: nothing
        recorded which fields they touched.

        **Public.** No authentication is required, and sending credentials changes nothing about the answer. The OEKG SPARQL endpoint already serves the same data, so a token here would protect nothing while making published research records awkward to read. (The reference page draws a **closed** padlock here. It marks a security requirement the reader already meets, not a protected endpoint -- on that page the closed padlock is the public one.)
      parameters:
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - triples
        description: '`triples` adds the stored payload of each entry, so that a legible
          summary never becomes the only account. A value this endpoint does not offer
          is refused with `400` rather than ignored, and the refusal happens before
          anything is written, so nothing was written when one arrives. Values are
          comma-separated, which matters once an endpoint offers two; none offers
          two yet, and the enum says which one it offers.'
      - in: query
        name: page
        schema:
          type: integer
        description: Which page of the result to return. 1-based.
      - in: query
        name: page_size
        schema:
          type: integer
        description: 'How many entries a page holds. Defaults to 20 and is capped
          at 100: this endpoint is public, and no public collection here has an unbounded
          mode.'
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BundleHistoryEntryPage'
          description: 'A page of entries, newest first -- a history is read from
            the present backwards. Each names the verb, the actor as a username, the
            resource, the versions either side of the write, and the fields that changed.
            `changes` is `null` rather than `[]` where there cannot be a summary:
            an empty list would say that nothing changed, and what is known is that
            nothing recorded *what* changed.'
  /api/v0/scenario-bundles/{uid}/scenarios/:
    get:
      operationId: scenario_bundles_scenarios_list
      description: |-
        List this bundle's parts of one kind.

        Paginated, although the collection is bounded by its bundle: this is a
        public endpoint and no public collection here has an unbounded mode.
        The nested form inside a bundle read is the exception, and a deliberate
        one -- that one has to be complete, because a client sends it back.

        **Public.** No authentication is required, and sending credentials changes nothing about the answer. The OEKG SPARQL endpoint already serves the same data, so a token here would protect nothing while making published research records awkward to read. (The reference page draws a **closed** padlock here. It marks a security requirement the reader already meets, not a protected endpoint -- on that page the closed padlock is the public one.)
      parameters:
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: query
        name: page
        schema:
          type: integer
        description: Which page of the result to return. 1-based.
      - in: query
        name: page_size
        schema:
          type: integer
        description: 'How many entries a page holds. Defaults to 50 and is capped
          at 200: this endpoint is public, and no public collection here has an unbounded
          mode.'
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScenarioReadPage'
          description: A page of this bundle's scenario factsheets.
    post:
      operationId: scenario_bundles_scenarios_create
      description: |-
        Add one part to this bundle.

        The identifier is minted by the server, as everywhere in this API, and
        returned in `Location`. What is validated is the **whole bundle with
        this part in it**: every constraint in the OEKG shape is bundle-local,
        so a part on its own is not a unit the shape can judge, and validating
        one alone would pass vacuously in the places that matter.

        The version guarded, the ownership asked and the entity tag returned
        are all the bundle's. Two clients editing two different parts of one
        bundle therefore do conflict -- the price of one version per bundle,
        and deliberate: conflict granularity follows the aggregate root, and a
        part is not one.

        **Requires authentication**, and only an owner of this scenario bundle may write to it -- a bundle with no recorded owner can be changed by an administrator only. Ownership is the bundle's, whatever part of it this operation names. (The reference page draws an **open** padlock here. It marks a security requirement not yet met -- use *Authorize* -- not an unprotected endpoint.)
      parameters:
      - in: header
        name: If-Match
        schema:
          type: string
        description: 'The entity tag of the bundle state this write applies to, as
          returned in `ETag` by the read it was built from. **Required, with no opt-out**:
          without it a client that has never heard of the header would overwrite a
          change made since it read, and neither party would be told. `*` is refused
          as an absent header rather than honoured as a wildcard, because it satisfies
          the letter of the precondition while withholding the one thing the precondition
          is for. A weak validator (`W/"4"`) and a bare number are both read as the
          version they plainly name.'
        required: true
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Scenario'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Scenario'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Scenario'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not recognise.
            Reads here need none; writes do.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Authenticated, but not an owner of this scenario bundle. A
            bundle with no recorded owner is administrator-only.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The bundle moved between the read this write was prepared from
            and the write itself, so **nothing was written**. Read it again, apply
            the change to what comes back, and retry.
        '412':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` named a version, and it is not the current one.
            Nothing was written. The response says which version the bundle is at.'
        '428':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` was absent, so this write did not say which version
            it was editing and nothing was written. The response names the current
            entity tag to send.'
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '201':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
            Location:
              schema:
                type: string
              description: 'Where the created resource can be read. The identifier
                in it was minted by the server: this API accepts none from a client.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScenarioRead'
          description: Created. The body is the scenario factsheet as it now stands,
            `Location` names its URL and `ETag` the **bundle's** new version.
  /api/v0/scenario-bundles/{uid}/scenarios/{pid}/:
    get:
      operationId: scenario_bundles_scenarios_retrieve
      description: |-
        Read one part of a bundle, publicly.

        **Public.** No authentication is required, and sending credentials changes nothing about the answer. The OEKG SPARQL endpoint already serves the same data, so a token here would protect nothing while making published research records awkward to read. (The reference page draws a **closed** padlock here. It marks a security requirement the reader already meets, not a protected endpoint -- on that page the closed padlock is the public one.)
      parameters:
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: path
        name: pid
        schema:
          type: string
        description: The identifier of the part this address names -- a scenario factsheet
          or a study report, depending on the route.
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScenarioRead'
          description: 'The scenario factsheet: what a write accepts, plus `_meta`.
            `ETag` carries the **bundle''s** version, which is what a write to this
            part has to send back.'
    patch:
      operationId: scenario_bundles_scenarios_partial_update
      description: |-
        Change the fields this payload names, without touching its siblings.

        A key the payload does not mention is genuinely untouched. The part's
        existence is checked **before** the precondition, so a request for a
        part that is not there hears that rather than being told its `If-Match`
        is missing for something that does not exist.

        Like every write here it is judged by what it **introduces**: a
        violation the bundle already carried is reported in
        `pre_existing_violations` and does not refuse the write.

        **Requires authentication**, and only an owner of this scenario bundle may write to it -- a bundle with no recorded owner can be changed by an administrator only. Ownership is the bundle's, whatever part of it this operation names. (The reference page draws an **open** padlock here. It marks a security requirement not yet met -- use *Authorize* -- not an unprotected endpoint.)
      parameters:
      - in: header
        name: If-Match
        schema:
          type: string
        description: 'The entity tag of the bundle state this write applies to, as
          returned in `ETag` by the read it was built from. **Required, with no opt-out**:
          without it a client that has never heard of the header would overwrite a
          change made since it read, and neither party would be told. `*` is refused
          as an absent header rather than honoured as a wildcard, because it satisfies
          the letter of the precondition while withholding the one thing the precondition
          is for. A weak validator (`W/"4"`) and a bare number are both read as the
          version they plainly name.'
        required: true
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: path
        name: pid
        schema:
          type: string
        description: The identifier of the part this address names -- a scenario factsheet
          or a study report, depending on the route.
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchedScenario'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/PatchedScenario'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/PatchedScenario'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not recognise.
            Reads here need none; writes do.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Authenticated, but not an owner of this scenario bundle. A
            bundle with no recorded owner is administrator-only.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The bundle moved between the read this write was prepared from
            and the write itself, so **nothing was written**. Read it again, apply
            the change to what comes back, and retry.
        '412':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` named a version, and it is not the current one.
            Nothing was written. The response says which version the bundle is at.'
        '428':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` was absent, so this write did not say which version
            it was editing and nothing was written. The response names the current
            entity tag to send.'
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScenarioRead'
          description: Changed. The body is the scenario factsheet as it now stands
            and `ETag` is the bundle's new version.
    delete:
      operationId: scenario_bundles_scenarios_destroy
      description: |-
        Remove this part, and with it what only it holds.

        The same order as a patch -- bundle, part, caller, precondition -- and
        the same write path, because a delete is a write like any other: it is
        validated against the shape, guarded on the bundle's version and
        recorded in the history. What differs is the arithmetic in front of it,
        which is `oekg.removal`'s.

        No retyped confirmation token, unlike the whole-bundle delete. Ceremony
        is proportional to blast radius: this removes one bounded part that can
        be created again, and the history says what it held.

        **Requires authentication**, and only an owner of this scenario bundle may write to it -- a bundle with no recorded owner can be changed by an administrator only. Ownership is the bundle's, whatever part of it this operation names. (The reference page draws an **open** padlock here. It marks a security requirement not yet met -- use *Authorize* -- not an unprotected endpoint.)
      parameters:
      - in: header
        name: If-Match
        schema:
          type: string
        description: 'The entity tag of the bundle state this write applies to, as
          returned in `ETag` by the read it was built from. **Required, with no opt-out**:
          without it a client that has never heard of the header would overwrite a
          change made since it read, and neither party would be told. `*` is refused
          as an absent header rather than honoured as a wildcard, because it satisfies
          the letter of the precondition while withholding the one thing the precondition
          is for. A weak validator (`W/"4"`) and a bare number are both read as the
          version they plainly name.'
        required: true
      - in: path
        name: pid
        schema:
          type: string
        description: The identifier of the part this address names -- a scenario factsheet
          or a study report, depending on the route.
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not recognise.
            Reads here need none; writes do.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Authenticated, but not an owner of this scenario bundle. A
            bundle with no recorded owner is administrator-only.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The bundle moved between the read this write was prepared from
            and the write itself, so **nothing was written**. Read it again, apply
            the change to what comes back, and retry.
        '412':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` named a version, and it is not the current one.
            Nothing was written. The response says which version the bundle is at.'
        '428':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` was absent, so this write did not say which version
            it was editing and nothing was written. The response names the current
            entity tag to send.'
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Removal'
          description: 'Removed. The body names what was **deleted** and what was
            only **unlinked**, which no status code can say: a node another bundle
            still cites is kept and detached rather than destroyed. Only the downgraded
            nodes are listed -- the shared regions, authors and ontology terms every
            delete detaches are the rule, not the news.'
  /api/v0/scenario-bundles/{uid}/scenarios/{sid}/datasets/:
    get:
      operationId: scenario_bundles_scenarios_datasets_list
      description: |-
        List this scenario's links to data on this platform.

        **Public.** No authentication is required, and sending credentials changes nothing about the answer. The OEKG SPARQL endpoint already serves the same data, so a token here would protect nothing while making published research records awkward to read. (The reference page draws a **closed** padlock here. It marks a security requirement the reader already meets, not a protected endpoint -- on that page the closed padlock is the public one.)
      parameters:
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: query
        name: page
        schema:
          type: integer
        description: Which page of the result to return. 1-based.
      - in: query
        name: page_size
        schema:
          type: integer
        description: 'How many entries a page holds. Defaults to 50 and is capped
          at 200: this endpoint is public, and no public collection here has an unbounded
          mode.'
      - in: path
        name: sid
        schema:
          type: string
        description: The identifier of the scenario factsheet these dataset links
          hang off.
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DatasetLinkReadPage'
          description: 'A page of this scenario''s dataset links. Every link reports
            what it points at **now**: `_meta.resolvable` says whether the named target
            is still on this platform, and `_meta.tables` names the one table for
            `ref: table` or the catalogue entry''s current members for `ref: dataset`.
            That is computed per read and never stored. Both read `null` -- never
            `false` -- when the stored address is not a page on this platform, because
            `false` would claim the target had been deleted. **Resolution is not an
            expansion**: a reader needs it to tell a live citation from a dead one,
            so it is never opt-in.'
    post:
      operationId: scenario_bundles_scenarios_datasets_create
      description: |-
        Link this scenario to a table or dataset on this platform.

        Three keys and no more: `type` (`input` or `output`), `ref` (`table`
        or `dataset`) and the target's `name`. Everything the shape stores
        follows from them, which is the same fact that gives a link no `PATCH`.

        **The target is not checked.** A link may outlive what it points at --
        a bundle is a published research record, so *this scenario used table
        X* stays true after X is gone -- and blocking here would let one user
        make a stranger's table undeletable. Whether the citation still
        resolves is reported on every read instead.

        `ref: table` is reproducible and `ref: dataset` is current: a dataset
        reference resolves to the catalogue entry's members as they are today,
        not as they were when the link was written. Choosing between them is
        the client's call.

        **Requires authentication**, and only an owner of this scenario bundle may write to it -- a bundle with no recorded owner can be changed by an administrator only. Ownership is the bundle's, whatever part of it this operation names. (The reference page draws an **open** padlock here. It marks a security requirement not yet met -- use *Authorize* -- not an unprotected endpoint.)
      parameters:
      - in: header
        name: If-Match
        schema:
          type: string
        description: 'The entity tag of the bundle state this write applies to, as
          returned in `ETag` by the read it was built from. **Required, with no opt-out**:
          without it a client that has never heard of the header would overwrite a
          change made since it read, and neither party would be told. `*` is refused
          as an absent header rather than honoured as a wildcard, because it satisfies
          the letter of the precondition while withholding the one thing the precondition
          is for. A weak validator (`W/"4"`) and a bare number are both read as the
          version they plainly name.'
        required: true
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: path
        name: sid
        schema:
          type: string
        description: The identifier of the scenario factsheet these dataset links
          hang off.
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DatasetLink'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/DatasetLink'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/DatasetLink'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The payload named a key this link does not have, or a `type`
            or `ref` outside the two values each allows -- or the target named cannot
            be addressed on this platform. Nothing was written.
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not recognise.
            Reads here need none; writes do.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Authenticated, but not an owner of this scenario bundle. A
            bundle with no recorded owner is administrator-only.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'This scenario already links that target in that direction,
            or the bundle moved while this write was being prepared. A duplicate is
            refused rather than silently skipped: two nodes saying one thing would
            leave a later `DELETE` ambiguous, and a caller unable to tell *added*
            from *already there*.'
        '412':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` named a version, and it is not the current one.
            Nothing was written. The response says which version the bundle is at.'
        '428':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` was absent, so this write did not say which version
            it was editing and nothing was written. The response names the current
            entity tag to send.'
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '201':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
            Location:
              schema:
                type: string
              description: 'Where the created resource can be read. The identifier
                in it was minted by the server: this API accepts none from a client.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DatasetLinkRead'
          description: 'Created. `Location` names the link''s URL and `ETag` the bundle''s
            new version. Every link reports what it points at **now**: `_meta.resolvable`
            says whether the named target is still on this platform, and `_meta.tables`
            names the one table for `ref: table` or the catalogue entry''s current
            members for `ref: dataset`. That is computed per read and never stored.
            Both read `null` -- never `false` -- when the stored address is not a
            page on this platform, because `false` would claim the target had been
            deleted. **Resolution is not an expansion**: a reader needs it to tell
            a live citation from a dead one, so it is never opt-in.'
  /api/v0/scenario-bundles/{uid}/scenarios/{sid}/datasets/{did}/:
    get:
      operationId: scenario_bundles_scenarios_datasets_retrieve
      description: |-
        Read one dataset link, publicly.

        `_meta.target_iri` is the address actually stored. It is there because
        it is the only thing that stays true when `ref` comes back `null`: a
        link written before this API existed can point at an address this
        platform has no route for, and the writable payload then genuinely
        cannot express it.

        **Public.** No authentication is required, and sending credentials changes nothing about the answer. The OEKG SPARQL endpoint already serves the same data, so a token here would protect nothing while making published research records awkward to read. (The reference page draws a **closed** padlock here. It marks a security requirement the reader already meets, not a protected endpoint -- on that page the closed padlock is the public one.)
      parameters:
      - in: path
        name: did
        schema:
          type: string
        description: The dataset link's identifier.
        required: true
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: path
        name: sid
        schema:
          type: string
        description: The identifier of the scenario factsheet these dataset links
          hang off.
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DatasetLinkRead'
          description: 'One dataset link. Every link reports what it points at **now**:
            `_meta.resolvable` says whether the named target is still on this platform,
            and `_meta.tables` names the one table for `ref: table` or the catalogue
            entry''s current members for `ref: dataset`. That is computed per read
            and never stored. Both read `null` -- never `false` -- when the stored
            address is not a page on this platform, because `false` would claim the
            target had been deleted. **Resolution is not an expansion**: a reader
            needs it to tell a live citation from a dead one, so it is never opt-in.'
    delete:
      operationId: scenario_bundles_scenarios_datasets_destroy
      description: |-
        Remove one link. Its target is not touched and never was.

        A link is the only removable thing in this API with no children and
        nothing shared beneath it -- what it points at is an OEP table or
        dataset, which lives in Postgres and which no graph write may reach. It
        still goes through the typed walk, because the guard clause is what
        decides whether *this* node is only claimed by this scenario, and that
        is not a question the class alone answers.

        **Requires authentication**, and only an owner of this scenario bundle may write to it -- a bundle with no recorded owner can be changed by an administrator only. Ownership is the bundle's, whatever part of it this operation names. (The reference page draws an **open** padlock here. It marks a security requirement not yet met -- use *Authorize* -- not an unprotected endpoint.)
      parameters:
      - in: header
        name: If-Match
        schema:
          type: string
        description: 'The entity tag of the bundle state this write applies to, as
          returned in `ETag` by the read it was built from. **Required, with no opt-out**:
          without it a client that has never heard of the header would overwrite a
          change made since it read, and neither party would be told. `*` is refused
          as an absent header rather than honoured as a wildcard, because it satisfies
          the letter of the precondition while withholding the one thing the precondition
          is for. A weak validator (`W/"4"`) and a bare number are both read as the
          version they plainly name.'
        required: true
      - in: path
        name: did
        schema:
          type: string
        description: The dataset link's identifier.
        required: true
      - in: path
        name: sid
        schema:
          type: string
        description: The identifier of the scenario factsheet these dataset links
          hang off.
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not recognise.
            Reads here need none; writes do.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Authenticated, but not an owner of this scenario bundle. A
            bundle with no recorded owner is administrator-only.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The bundle moved between the read this write was prepared from
            and the write itself, so **nothing was written**. Read it again, apply
            the change to what comes back, and retry.
        '412':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` named a version, and it is not the current one.
            Nothing was written. The response says which version the bundle is at.'
        '428':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` was absent, so this write did not say which version
            it was editing and nothing was written. The response names the current
            entity tag to send.'
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Removal'
          description: 'Removed. The body names what was **deleted** and what was
            only **unlinked**, which no status code can say: a node another bundle
            still cites is kept and detached rather than destroyed. Only the downgraded
            nodes are listed -- the shared regions, authors and ontology terms every
            delete detaches are the rule, not the news.'
  /api/v0/scenario-bundles/{uid}/study-reports/:
    get:
      operationId: scenario_bundles_study_reports_list
      description: |-
        List this bundle's parts of one kind.

        Paginated, although the collection is bounded by its bundle: this is a
        public endpoint and no public collection here has an unbounded mode.
        The nested form inside a bundle read is the exception, and a deliberate
        one -- that one has to be complete, because a client sends it back.

        **Public.** No authentication is required, and sending credentials changes nothing about the answer. The OEKG SPARQL endpoint already serves the same data, so a token here would protect nothing while making published research records awkward to read. (The reference page draws a **closed** padlock here. It marks a security requirement the reader already meets, not a protected endpoint -- on that page the closed padlock is the public one.)
      parameters:
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: query
        name: page
        schema:
          type: integer
        description: Which page of the result to return. 1-based.
      - in: query
        name: page_size
        schema:
          type: integer
        description: 'How many entries a page holds. Defaults to 50 and is capped
          at 200: this endpoint is public, and no public collection here has an unbounded
          mode.'
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StudyReportReadPage'
          description: A page of this bundle's study reports.
    post:
      operationId: scenario_bundles_study_reports_create
      description: |-
        Add one part to this bundle.

        The identifier is minted by the server, as everywhere in this API, and
        returned in `Location`. What is validated is the **whole bundle with
        this part in it**: every constraint in the OEKG shape is bundle-local,
        so a part on its own is not a unit the shape can judge, and validating
        one alone would pass vacuously in the places that matter.

        The version guarded, the ownership asked and the entity tag returned
        are all the bundle's. Two clients editing two different parts of one
        bundle therefore do conflict -- the price of one version per bundle,
        and deliberate: conflict granularity follows the aggregate root, and a
        part is not one.

        **Requires authentication**, and only an owner of this scenario bundle may write to it -- a bundle with no recorded owner can be changed by an administrator only. Ownership is the bundle's, whatever part of it this operation names. (The reference page draws an **open** padlock here. It marks a security requirement not yet met -- use *Authorize* -- not an unprotected endpoint.)
      parameters:
      - in: header
        name: If-Match
        schema:
          type: string
        description: 'The entity tag of the bundle state this write applies to, as
          returned in `ETag` by the read it was built from. **Required, with no opt-out**:
          without it a client that has never heard of the header would overwrite a
          change made since it read, and neither party would be told. `*` is refused
          as an absent header rather than honoured as a wildcard, because it satisfies
          the letter of the precondition while withholding the one thing the precondition
          is for. A weak validator (`W/"4"`) and a bare number are both read as the
          version they plainly name.'
        required: true
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StudyReport'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/StudyReport'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/StudyReport'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not recognise.
            Reads here need none; writes do.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Authenticated, but not an owner of this scenario bundle. A
            bundle with no recorded owner is administrator-only.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The bundle moved between the read this write was prepared from
            and the write itself, so **nothing was written**. Read it again, apply
            the change to what comes back, and retry.
        '412':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` named a version, and it is not the current one.
            Nothing was written. The response says which version the bundle is at.'
        '428':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` was absent, so this write did not say which version
            it was editing and nothing was written. The response names the current
            entity tag to send.'
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '201':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
            Location:
              schema:
                type: string
              description: 'Where the created resource can be read. The identifier
                in it was minted by the server: this API accepts none from a client.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StudyReportRead'
          description: Created. The body is the study report as it now stands, `Location`
            names its URL and `ETag` the **bundle's** new version.
  /api/v0/scenario-bundles/{uid}/study-reports/{pid}/:
    get:
      operationId: scenario_bundles_study_reports_retrieve
      description: |-
        Read one part of a bundle, publicly.

        **Public.** No authentication is required, and sending credentials changes nothing about the answer. The OEKG SPARQL endpoint already serves the same data, so a token here would protect nothing while making published research records awkward to read. (The reference page draws a **closed** padlock here. It marks a security requirement the reader already meets, not a protected endpoint -- on that page the closed padlock is the public one.)
      parameters:
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: path
        name: pid
        schema:
          type: string
        description: The identifier of the part this address names -- a scenario factsheet
          or a study report, depending on the route.
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StudyReportRead'
          description: 'The study report: what a write accepts, plus `_meta`. `ETag`
            carries the **bundle''s** version, which is what a write to this part
            has to send back.'
    patch:
      operationId: scenario_bundles_study_reports_partial_update
      description: |-
        Change the fields this payload names, without touching its siblings.

        A key the payload does not mention is genuinely untouched. The part's
        existence is checked **before** the precondition, so a request for a
        part that is not there hears that rather than being told its `If-Match`
        is missing for something that does not exist.

        Like every write here it is judged by what it **introduces**: a
        violation the bundle already carried is reported in
        `pre_existing_violations` and does not refuse the write.

        **Requires authentication**, and only an owner of this scenario bundle may write to it -- a bundle with no recorded owner can be changed by an administrator only. Ownership is the bundle's, whatever part of it this operation names. (The reference page draws an **open** padlock here. It marks a security requirement not yet met -- use *Authorize* -- not an unprotected endpoint.)
      parameters:
      - in: header
        name: If-Match
        schema:
          type: string
        description: 'The entity tag of the bundle state this write applies to, as
          returned in `ETag` by the read it was built from. **Required, with no opt-out**:
          without it a client that has never heard of the header would overwrite a
          change made since it read, and neither party would be told. `*` is refused
          as an absent header rather than honoured as a wildcard, because it satisfies
          the letter of the precondition while withholding the one thing the precondition
          is for. A weak validator (`W/"4"`) and a bare number are both read as the
          version they plainly name.'
        required: true
      - in: query
        name: expand
        schema:
          type: string
          enum:
          - labels
        description: '`labels` resolves the ontology terms this resource picks into
          `_meta.labels`, from a small label subset rather than the full OEO. A value
          this endpoint does not offer is refused with `400` rather than ignored,
          and the refusal happens before anything is written, so nothing was written
          when one arrives. Values are comma-separated, which matters once an endpoint
          offers two; none offers two yet, and the enum says which one it offers.'
      - in: path
        name: pid
        schema:
          type: string
        description: The identifier of the part this address names -- a scenario factsheet
          or a study report, depending on the route.
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PatchedStudyReport'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/PatchedStudyReport'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/PatchedStudyReport'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not recognise.
            Reads here need none; writes do.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Authenticated, but not an owner of this scenario bundle. A
            bundle with no recorded owner is administrator-only.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The bundle moved between the read this write was prepared from
            and the write itself, so **nothing was written**. Read it again, apply
            the change to what comes back, and retry.
        '412':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` named a version, and it is not the current one.
            Nothing was written. The response says which version the bundle is at.'
        '428':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` was absent, so this write did not say which version
            it was editing and nothing was written. The response names the current
            entity tag to send.'
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/StudyReportRead'
          description: Changed. The body is the study report as it now stands and
            `ETag` is the bundle's new version.
    delete:
      operationId: scenario_bundles_study_reports_destroy
      description: |-
        Remove this part, and with it what only it holds.

        The same order as a patch -- bundle, part, caller, precondition -- and
        the same write path, because a delete is a write like any other: it is
        validated against the shape, guarded on the bundle's version and
        recorded in the history. What differs is the arithmetic in front of it,
        which is `oekg.removal`'s.

        No retyped confirmation token, unlike the whole-bundle delete. Ceremony
        is proportional to blast radius: this removes one bounded part that can
        be created again, and the history says what it held.

        **Requires authentication**, and only an owner of this scenario bundle may write to it -- a bundle with no recorded owner can be changed by an administrator only. Ownership is the bundle's, whatever part of it this operation names. (The reference page draws an **open** padlock here. It marks a security requirement not yet met -- use *Authorize* -- not an unprotected endpoint.)
      parameters:
      - in: header
        name: If-Match
        schema:
          type: string
        description: 'The entity tag of the bundle state this write applies to, as
          returned in `ETag` by the read it was built from. **Required, with no opt-out**:
          without it a client that has never heard of the header would overwrite a
          change made since it read, and neither party would be told. `*` is refused
          as an absent header rather than honoured as a wildcard, because it satisfies
          the letter of the precondition while withholding the one thing the precondition
          is for. A weak validator (`W/"4"`) and a bare number are both read as the
          version they plainly name.'
        required: true
      - in: path
        name: pid
        schema:
          type: string
        description: The identifier of the part this address names -- a scenario factsheet
          or a study report, depending on the route.
        required: true
      - in: path
        name: uid
        schema:
          type: string
        description: The scenario bundle's identifier, as minted by the server on
          create and returned in `_meta.uid`. A pipeline holding no state finds it
          again with `GET /api/v0/scenario-bundles/?acronym=...`.
        required: true
      tags:
      - scenario-bundles
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Refused, and **nothing was written**. The body is either `detail`
            with one sentence, or -- when the payload failed the serializer -- a map
            from field name to what was wrong with it. The payload named a key the
            closed bundle shape does not have, or a value the shape's own `sh:in`
            list does not allow, or the change would introduce a violation of the
            OEKG shape -- `violations` then names them, and `pre_existing_violations`
            counts the ones this write is not blamed for. A write is judged by what
            it *introduces*, so a bundle that was already non-conforming can still
            be repaired through this API.
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not recognise.
            Reads here need none; writes do.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Authenticated, but not an owner of this scenario bundle. A
            bundle with no recorded owner is administrator-only.
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No such scenario bundle, or no such resource within it.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The bundle moved between the read this write was prepared from
            and the write itself, so **nothing was written**. Read it again, apply
            the change to what comes back, and retry.
        '412':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` named a version, and it is not the current one.
            Nothing was written. The response says which version the bundle is at.'
        '428':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`If-Match` was absent, so this write did not say which version
            it was editing and nothing was written. The response names the current
            entity tag to send.'
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Throttled. These endpoints are public to read, so they carry
            a ceiling for anonymous callers and a separate one per account. `Retry-After`
            says how long to wait.
        '503':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The OEKG graph store could not be reached, or the shape this
            API validates against is not installed on this server. Neither is an answer
            about the bundle: nothing was read and nothing was written.'
        '200':
          headers:
            ETag:
              schema:
                type: string
              description: The bundle's current version. Send it back in `If-Match`
                on the next write. It is returned on **every** response that carries
                one, writes included, so a pipeline reads once per run and chains
                its writes; only a lost response forces a re-read. A sub-resource
                has no version of its own -- the tag here is always the containing
                bundle's.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Removal'
          description: 'Removed. The body names what was **deleted** and what was
            only **unlinked**, which no status code can say: a node another bundle
            still cites is kept and detached rather than destroyed. Only the downgraded
            nodes are listed -- the shared regions, authors and ontology terms every
            delete detaches are the rule, not the news.'
  /api/v0/schema/:
    get:
      operationId: schema_retrieve
      description: |-
        OpenApi3 schema for this API. Format can be selected via content negotiation.

        - YAML: application/vnd.oai.openapi
        - JSON: application/vnd.oai.openapi+json
      parameters:
      - in: query
        name: format
        schema:
          type: string
          enum:
          - json
          - yaml
      - in: query
        name: lang
        schema:
          type: string
          enum:
          - af
          - ar
          - ar-dz
          - ast
          - az
          - be
          - bg
          - bn
          - br
          - bs
          - ca
          - ckb
          - cs
          - cy
          - da
          - de
          - dsb
          - el
          - en
          - en-au
          - en-gb
          - eo
          - es
          - es-ar
          - es-co
          - es-mx
          - es-ni
          - es-ve
          - et
          - eu
          - fa
          - fi
          - fr
          - fy
          - ga
          - gd
          - gl
          - he
          - hi
          - hr
          - hsb
          - hu
          - hy
          - ia
          - id
          - ig
          - io
          - is
          - it
          - ja
          - ka
          - kab
          - kk
          - km
          - kn
          - ko
          - ky
          - lb
          - lt
          - lv
          - mk
          - ml
          - mn
          - mr
          - ms
          - my
          - nb
          - ne
          - nl
          - nn
          - os
          - pa
          - pl
          - pt
          - pt-br
          - ro
          - ru
          - sk
          - sl
          - sq
          - sr
          - sr-latn
          - sv
          - sw
          - ta
          - te
          - tg
          - th
          - tk
          - tr
          - tt
          - udm
          - ug
          - uk
          - ur
          - uz
          - vi
          - zh-hans
          - zh-hant
      tags:
      - schema
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '200':
          content:
            application/vnd.oai.openapi:
              schema:
                type: object
                additionalProperties: {}
            application/yaml:
              schema:
                type: object
                additionalProperties: {}
            application/vnd.oai.openapi+json:
              schema:
                type: object
                additionalProperties: {}
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: ''
  /api/v0/tables/{table}/:
    get:
      operationId: tables_retrieve
      description: 'The table''s structure: its columns, its indexes and its constraints.
        Not its rows -- those are at `rows/`.'
      summary: Describe a table
      parameters:
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`name`, `columns`, `indexed` and `constraints`, each keyed
            by name.'
    post:
      operationId: tables_create
      description: Alters an existing table. **The payload is at the top level here**,
        unlike the `PUT` on this same address, which reads it out of `query`. `type`
        decides which kind of change is meant; anything else is refused.
      summary: Change a table's columns or constraints
      parameters:
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TableAlter'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/TableAlter'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/TableAlter'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: What the queued change came to.
    put:
      operationId: tables_update
      description: |-
        Creates the table and its metadata row. **Two things about this endpoint catch people out.** The target schema comes from the `is_sandbox` query parameter, not from the payload. And table names are global -- a name already taken anywhere on the platform is a `409`, whichever schema or topic holds it.

        The payload sits under a `query` key rather than at the top level.
      summary: Create a table
      parameters:
      - in: query
        name: is_sandbox
        schema:
          type: boolean
        description: '**Which schema the table is created in, and the one thing worth
          getting right here.** Send `true` and the table lands in the sandbox schema,
          which is where anything not meant to be published belongs. Omit it and the
          table is created in the public `data` schema, visible to everyone -- there
          is no confirmation step and no undo but deleting the table.'
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TableCreate'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/TableCreate'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/TableCreate'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: A table of that name already exists. Table names are global.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Created. The body is empty; the table is at this URL.
    delete:
      operationId: tables_destroy
      description: Removes the table and its metadata. Irreversible, and it takes
        the rows with it.
      summary: Delete a table
      parameters:
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Deleted. The body is empty.
  /api/v0/tables/{table}/bulk-upload/:
    post:
      operationId: tables_bulk_upload_create
      description: |-
        **The request body is the CSV itself**, not JSON wrapping one. Rows are appended in one transaction: either the whole upload lands or none of it does. It bypasses the edit journal, so there is no per-row history for what it writes -- the `BulkLoadEvent` it leaves is the upload's provenance.

        Send it gzipped (`Content-Encoding: gzip`) unless the file is small: the platform is not the bottleneck on a large upload, the client's uplink is, and CSV compresses well enough to change what is reachable.

        At most one upload per account runs at a time; a second answers `429` with `Retry-After` and writes nothing.
      summary: Append a CSV to a table
      parameters:
      - in: query
        name: delimiter
        schema:
          type: string
        description: 'The CSV delimiter of the body. **Required**: it is not guessed,
          because guessing it wrong loads a whole file into the wrong columns.'
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      requestBody:
        content:
          text/csv:
            schema:
              type: string
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Appended. `rows` is how many, `id_range` the first and last
            id written, and `event_id` names the BulkLoadEvent this upload left.
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Another upload of yours is already running, or the platform
            is at its limit. Nothing was written and no event recorded. `Retry-After`
            says how long to wait.
  /api/v0/tables/{table}/columns/{column}:
    get:
      operationId: tables_columns_retrieve
      description: One column's definition, or the whole set when the address ends
        at `columns/`.
      summary: Describe a column, or every column
      parameters:
      - in: path
        name: column
        schema:
          type: string
        description: The column's name. Omit it for every column.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The column definitions, keyed by name.
    post:
      operationId: tables_columns_create
      description: |-
        Changes an existing column's definition.

        The payload sits under a `query` key rather than at the top level.
      summary: Alter a column
      parameters:
      - in: path
        name: column
        schema:
          type: string
        description: The column's name.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: What the change came to.
    put:
      operationId: tables_columns_update
      description: |-
        Adds a column to an existing table.

        The payload sits under a `query` key rather than at the top level.
      summary: Add a column
      parameters:
      - in: path
        name: column
        schema:
          type: string
        description: The column's name.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Added. The body is empty.
  /api/v0/tables/{table}/meta/:
    get:
      operationId: tables_meta_retrieve
      description: The table's OEMetadata document, as stored. A table carries one
        resource, so a reader wanting the table's own fields wants `resources[0]`.
      summary: Read a table's metadata
      parameters:
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - 'Schema: Meta'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The OEMetadata document.
    post:
      operationId: tables_meta_create
      description: Replaces the stored OEMetadata document. The payload is the document
        itself, at the top level -- not wrapped in `query`. An older version is converted
        to the current one, the column list is synchronised with the table's actual
        columns, and the result is validated before anything is stored; a document
        that fails validation is refused and nothing changes. The table's keywords
        become its tags on this platform.
      summary: Set a table's metadata
      parameters:
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - 'Schema: Meta'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: {}
          application/x-www-form-urlencoded:
            schema:
              type: object
              additionalProperties: {}
          multipart/form-data:
            schema:
              type: object
              additionalProperties: {}
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The metadata as it was stored.
  /api/v0/tables/{table}/move_publish/{topic}/:
    post:
      operationId: tables_move_publish_create
      description: Moves the table into a topic and marks it published. Needs administrator
        permission on the table. An embargo may be given either at the top level or
        inside `query` -- this endpoint reads both, which is worth knowing because
        its neighbours do not.
      summary: Publish a table under a topic
      parameters:
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      - in: path
        name: topic
        schema:
          type: string
        description: The topic to publish under.
        required: true
      tags:
      - tables
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: {}
          application/x-www-form-urlencoded:
            schema:
              type: object
              additionalProperties: {}
          multipart/form-data:
            schema:
              type: object
              additionalProperties: {}
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Published. The body is empty.
  /api/v0/tables/{table}/rows/{row_id}:
    get:
      operationId: tables_rows_retrieve
      description: 'One row by id, or the rows a filter selects. The filter parameters
        and a row id are mutually exclusive: an id already names one row, so sending
        both is refused rather than silently resolved one way.'
      summary: Read rows
      parameters:
      - in: query
        name: column
        schema:
          type: string
        description: Return only this column. Repeat the parameter for several. Each
          must be a Postgres identifier; anything else is refused rather than ignored.
      - in: query
        name: form
        schema:
          type: string
        description: '`csv` returns the rows as CSV instead of JSON.'
      - in: query
        name: limit
        schema:
          type: integer
        description: At most this many rows. Not accepted together with a row id.
      - in: query
        name: offset
        schema:
          type: integer
        description: Skip this many rows first. Not accepted together with a row id.
      - in: query
        name: orderby
        schema:
          type: string
        description: Sort by this column. Not accepted together with a row id.
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      - in: query
        name: where
        schema:
          type: string
        description: A filter, as `column=value`, `column>value`, `column<value` or
          the negated forms. Repeat the parameter to apply several. Not accepted together
          with a row id in the path -- the id already names the row.
      tags:
      - tables
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The rows, as a list of objects keyed by column name.
    post:
      operationId: tables_rows_create
      description: |-
        At `rows/new` this inserts and answers `201`. At `rows/<id>` it updates that row, and at `rows/` it updates the rows a filter selects.

        The payload sits under a `query` key rather than at the top level.
      summary: Insert or update rows
      parameters:
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Row'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Row'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Row'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The rows as they now stand.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Inserted.
    put:
      operationId: tables_rows_update
      description: |-
        Updates the row at this id, or inserts it there if it is not yet taken. **An id never changes**: an `id` in the payload that disagrees with the one in the address is a `409` rather than a move. Requires an id -- `rows/new` is a `POST`.

        The payload sits under a `query` key rather than at the top level.
      summary: Put one row at an id
      parameters:
      - in: path
        name: row_id
        schema:
          type: integer
        description: The row's id.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Row'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Row'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Row'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: A table of that name already exists. Table names are global.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Updated.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Inserted at that id.
    delete:
      operationId: tables_rows_destroy
      description: One row by id, or the rows a `where` filter selects. Deleting with
        neither deletes every row in the table.
      summary: Delete rows
      parameters:
      - in: query
        name: column
        schema:
          type: string
        description: Return only this column. Repeat the parameter for several. Each
          must be a Postgres identifier; anything else is refused rather than ignored.
      - in: query
        name: form
        schema:
          type: string
        description: '`csv` returns the rows as CSV instead of JSON.'
      - in: query
        name: limit
        schema:
          type: integer
        description: At most this many rows. Not accepted together with a row id.
      - in: query
        name: offset
        schema:
          type: integer
        description: Skip this many rows first. Not accepted together with a row id.
      - in: query
        name: orderby
        schema:
          type: string
        description: Sort by this column. Not accepted together with a row id.
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      - in: query
        name: where
        schema:
          type: string
        description: A filter, as `column=value`, `column>value`, `column<value` or
          the negated forms. Repeat the parameter to apply several. Not accepted together
          with a row id in the path -- the id already names the row.
      tags:
      - tables
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: What was deleted.
  /api/v0/tables/{table}/rows/new:
    get:
      operationId: tables_rows_new_retrieve
      description: 'One row by id, or the rows a filter selects. The filter parameters
        and a row id are mutually exclusive: an id already names one row, so sending
        both is refused rather than silently resolved one way.'
      summary: Read rows
      parameters:
      - in: query
        name: column
        schema:
          type: string
        description: Return only this column. Repeat the parameter for several. Each
          must be a Postgres identifier; anything else is refused rather than ignored.
      - in: query
        name: form
        schema:
          type: string
        description: '`csv` returns the rows as CSV instead of JSON.'
      - in: query
        name: limit
        schema:
          type: integer
        description: At most this many rows. Not accepted together with a row id.
      - in: query
        name: offset
        schema:
          type: integer
        description: Skip this many rows first. Not accepted together with a row id.
      - in: query
        name: orderby
        schema:
          type: string
        description: Sort by this column. Not accepted together with a row id.
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      - in: query
        name: where
        schema:
          type: string
        description: A filter, as `column=value`, `column>value`, `column<value` or
          the negated forms. Repeat the parameter to apply several. Not accepted together
          with a row id in the path -- the id already names the row.
      tags:
      - tables
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The rows, as a list of objects keyed by column name.
    post:
      operationId: tables_rows_new_create
      description: |-
        At `rows/new` this inserts and answers `201`. At `rows/<id>` it updates that row, and at `rows/` it updates the rows a filter selects.

        The payload sits under a `query` key rather than at the top level.
      summary: Insert or update rows
      parameters:
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Row'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Row'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Row'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The rows as they now stand.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Inserted.
    put:
      operationId: tables_rows_new_update
      description: |-
        Updates the row at this id, or inserts it there if it is not yet taken. **An id never changes**: an `id` in the payload that disagrees with the one in the address is a `409` rather than a move. Requires an id -- `rows/new` is a `POST`.

        The payload sits under a `query` key rather than at the top level.
      summary: Put one row at an id
      parameters:
      - in: path
        name: row_id
        schema:
          type: integer
        description: The row's id.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Row'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Row'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Row'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: A table of that name already exists. Table names are global.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Updated.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Inserted at that id.
    delete:
      operationId: tables_rows_new_destroy
      description: One row by id, or the rows a `where` filter selects. Deleting with
        neither deletes every row in the table.
      summary: Delete rows
      parameters:
      - in: query
        name: column
        schema:
          type: string
        description: Return only this column. Repeat the parameter for several. Each
          must be a Postgres identifier; anything else is refused rather than ignored.
      - in: query
        name: form
        schema:
          type: string
        description: '`csv` returns the rows as CSV instead of JSON.'
      - in: query
        name: limit
        schema:
          type: integer
        description: At most this many rows. Not accepted together with a row id.
      - in: query
        name: offset
        schema:
          type: integer
        description: Skip this many rows first. Not accepted together with a row id.
      - in: query
        name: orderby
        schema:
          type: string
        description: Sort by this column. Not accepted together with a row id.
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      - in: query
        name: where
        schema:
          type: string
        description: A filter, as `column=value`, `column>value`, `column<value` or
          the negated forms. Repeat the parameter to apply several. Not accepted together
          with a row id in the path -- the id already names the row.
      tags:
      - tables
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: What was deleted.
  /api/v0/tables/{table}/unpublish:
    post:
      operationId: tables_unpublish_create
      description: Marks the table not published. It keeps its topic and its rows;
        what changes is whether it is listed. Needs administrator permission on the
        table.
      summary: Unpublish a table
      parameters:
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - tables
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Unpublished. The body is empty.
  /api/v0/schema/{schema}/tables/{table}/:
    get:
      operationId: schema_[\w\d_]_tables_retrieve
      description: |-
        The table's structure: its columns, its indexes and its constraints. Not its rows -- those are at `rows/`.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Describe a table
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: '`name`, `columns`, `indexed` and `constraints`, each keyed
            by name.'
      deprecated: true
    post:
      operationId: schema_[\w\d_]_tables_create
      description: |-
        Alters an existing table. **The payload is at the top level here**, unlike the `PUT` on this same address, which reads it out of `query`. `type` decides which kind of change is meant; anything else is refused.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Change a table's columns or constraints
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TableAlter'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/TableAlter'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/TableAlter'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: What the queued change came to.
      deprecated: true
    put:
      operationId: schema_[\w\d_]_tables_update
      description: |-
        Creates the table and its metadata row. **Two things about this endpoint catch people out.** The target schema comes from the `is_sandbox` query parameter, not from the payload. And table names are global -- a name already taken anywhere on the platform is a `409`, whichever schema or topic holds it.

        The payload sits under a `query` key rather than at the top level.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Create a table
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: query
        name: is_sandbox
        schema:
          type: boolean
        description: '**Which schema the table is created in, and the one thing worth
          getting right here.** Send `true` and the table lands in the sandbox schema,
          which is where anything not meant to be published belongs. Omit it and the
          table is created in the public `data` schema, visible to everyone -- there
          is no confirmation step and no undo but deleting the table.'
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TableCreate'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/TableCreate'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/TableCreate'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: A table of that name already exists. Table names are global.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Created. The body is empty; the table is at this URL.
      deprecated: true
    delete:
      operationId: schema_[\w\d_]_tables_destroy
      description: |-
        Removes the table and its metadata. Irreversible, and it takes the rows with it.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Delete a table
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Deleted. The body is empty.
      deprecated: true
  /api/v0/schema/{schema}/tables/{table}/bulk-upload/:
    post:
      operationId: schema_[\w\d_]_tables_bulk_upload_create
      description: |-
        **The request body is the CSV itself**, not JSON wrapping one. Rows are appended in one transaction: either the whole upload lands or none of it does. It bypasses the edit journal, so there is no per-row history for what it writes -- the `BulkLoadEvent` it leaves is the upload's provenance.

        Send it gzipped (`Content-Encoding: gzip`) unless the file is small: the platform is not the bottleneck on a large upload, the client's uplink is, and CSV compresses well enough to change what is reachable.

        At most one upload per account runs at a time; a second answers `429` with `Retry-After` and writes nothing.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/bulk-upload/` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Append a CSV to a table
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: query
        name: delimiter
        schema:
          type: string
        description: 'The CSV delimiter of the body. **Required**: it is not guessed,
          because guessing it wrong loads a whole file into the wrong columns.'
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      requestBody:
        content:
          text/csv:
            schema:
              type: string
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Appended. `rows` is how many, `id_range` the first and last
            id written, and `event_id` names the BulkLoadEvent this upload left.
        '429':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Another upload of yours is already running, or the platform
            is at its limit. Nothing was written and no event recorded. `Retry-After`
            says how long to wait.
      deprecated: true
  /api/v0/schema/{schema}/tables/{table}/columns/{column}:
    get:
      operationId: schema_[\w\d_]_tables_columns_retrieve
      description: |-
        One column's definition, or the whole set when the address ends at `columns/`.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/columns/{column}` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Describe a column, or every column
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: column
        schema:
          type: string
        description: The column's name. Omit it for every column.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The column definitions, keyed by name.
      deprecated: true
    post:
      operationId: schema_[\w\d_]_tables_columns_create
      description: |-
        Changes an existing column's definition.

        The payload sits under a `query` key rather than at the top level.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/columns/{column}` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Alter a column
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: column
        schema:
          type: string
        description: The column's name.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: What the change came to.
      deprecated: true
    put:
      operationId: schema_[\w\d_]_tables_columns_update
      description: |-
        Adds a column to an existing table.

        The payload sits under a `query` key rather than at the top level.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/columns/{column}` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Add a column
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: column
        schema:
          type: string
        description: The column's name.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/QueryWrapped'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Added. The body is empty.
      deprecated: true
  /api/v0/schema/{schema}/tables/{table}/meta/:
    get:
      operationId: schema_[\w\d_]_tables_meta_retrieve
      description: |-
        The table's OEMetadata document, as stored. A table carries one resource, so a reader wanting the table's own fields wants `resources[0]`.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/meta/` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Read a table's metadata
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - 'Schema: Meta'
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The OEMetadata document.
      deprecated: true
    post:
      operationId: schema_[\w\d_]_tables_meta_create
      description: |-
        Replaces the stored OEMetadata document. The payload is the document itself, at the top level -- not wrapped in `query`. An older version is converted to the current one, the column list is synchronised with the table's actual columns, and the result is validated before anything is stored; a document that fails validation is refused and nothing changes. The table's keywords become its tags on this platform.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/meta/` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Set a table's metadata
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - 'Schema: Meta'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: {}
          application/x-www-form-urlencoded:
            schema:
              type: object
              additionalProperties: {}
          multipart/form-data:
            schema:
              type: object
              additionalProperties: {}
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The metadata as it was stored.
      deprecated: true
  /api/v0/schema/{schema}/tables/{table}/move_publish/{topic}/:
    post:
      operationId: schema_[\w\d_]_tables_move_publish_create
      description: |-
        Moves the table into a topic and marks it published. Needs administrator permission on the table. An embargo may be given either at the top level or inside `query` -- this endpoint reads both, which is worth knowing because its neighbours do not.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/move_publish/{topic}/` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Publish a table under a topic
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      - in: path
        name: topic
        schema:
          type: string
        description: The topic to publish under.
        required: true
      tags:
      - schema
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: {}
          application/x-www-form-urlencoded:
            schema:
              type: object
              additionalProperties: {}
          multipart/form-data:
            schema:
              type: object
              additionalProperties: {}
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Published. The body is empty.
      deprecated: true
  /api/v0/schema/{schema}/tables/{table}/rows/{row_id}:
    get:
      operationId: schema_[\w\d_]_tables_rows_retrieve
      description: |-
        One row by id, or the rows a filter selects. The filter parameters and a row id are mutually exclusive: an id already names one row, so sending both is refused rather than silently resolved one way.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/rows/{row_id}` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Read rows
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: query
        name: column
        schema:
          type: string
        description: Return only this column. Repeat the parameter for several. Each
          must be a Postgres identifier; anything else is refused rather than ignored.
      - in: query
        name: form
        schema:
          type: string
        description: '`csv` returns the rows as CSV instead of JSON.'
      - in: query
        name: limit
        schema:
          type: integer
        description: At most this many rows. Not accepted together with a row id.
      - in: query
        name: offset
        schema:
          type: integer
        description: Skip this many rows first. Not accepted together with a row id.
      - in: query
        name: orderby
        schema:
          type: string
        description: Sort by this column. Not accepted together with a row id.
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      - in: query
        name: where
        schema:
          type: string
        description: A filter, as `column=value`, `column>value`, `column<value` or
          the negated forms. Repeat the parameter to apply several. Not accepted together
          with a row id in the path -- the id already names the row.
      tags:
      - schema
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The rows, as a list of objects keyed by column name.
      deprecated: true
    post:
      operationId: schema_[\w\d_]_tables_rows_create
      description: |-
        At `rows/new` this inserts and answers `201`. At `rows/<id>` it updates that row, and at `rows/` it updates the rows a filter selects.

        The payload sits under a `query` key rather than at the top level.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/rows/{row_id}` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Insert or update rows
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Row'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Row'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Row'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The rows as they now stand.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Inserted.
      deprecated: true
    put:
      operationId: schema_[\w\d_]_tables_rows_update
      description: |-
        Updates the row at this id, or inserts it there if it is not yet taken. **An id never changes**: an `id` in the payload that disagrees with the one in the address is a `409` rather than a move. Requires an id -- `rows/new` is a `POST`.

        The payload sits under a `query` key rather than at the top level.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/rows/{row_id}` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Put one row at an id
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: row_id
        schema:
          type: integer
        description: The row's id.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Row'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Row'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Row'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: A table of that name already exists. Table names are global.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Updated.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Inserted at that id.
      deprecated: true
    delete:
      operationId: schema_[\w\d_]_tables_rows_destroy
      description: |-
        One row by id, or the rows a `where` filter selects. Deleting with neither deletes every row in the table.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/rows/{row_id}` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Delete rows
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: query
        name: column
        schema:
          type: string
        description: Return only this column. Repeat the parameter for several. Each
          must be a Postgres identifier; anything else is refused rather than ignored.
      - in: query
        name: form
        schema:
          type: string
        description: '`csv` returns the rows as CSV instead of JSON.'
      - in: query
        name: limit
        schema:
          type: integer
        description: At most this many rows. Not accepted together with a row id.
      - in: query
        name: offset
        schema:
          type: integer
        description: Skip this many rows first. Not accepted together with a row id.
      - in: query
        name: orderby
        schema:
          type: string
        description: Sort by this column. Not accepted together with a row id.
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      - in: query
        name: where
        schema:
          type: string
        description: A filter, as `column=value`, `column>value`, `column<value` or
          the negated forms. Repeat the parameter to apply several. Not accepted together
          with a row id in the path -- the id already names the row.
      tags:
      - schema
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: What was deleted.
      deprecated: true
  /api/v0/schema/{schema}/tables/{table}/rows/new:
    get:
      operationId: schema_[\w\d_]_tables_rows_new_retrieve
      description: |-
        One row by id, or the rows a filter selects. The filter parameters and a row id are mutually exclusive: an id already names one row, so sending both is refused rather than silently resolved one way.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/rows/new` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Read rows
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: query
        name: column
        schema:
          type: string
        description: Return only this column. Repeat the parameter for several. Each
          must be a Postgres identifier; anything else is refused rather than ignored.
      - in: query
        name: form
        schema:
          type: string
        description: '`csv` returns the rows as CSV instead of JSON.'
      - in: query
        name: limit
        schema:
          type: integer
        description: At most this many rows. Not accepted together with a row id.
      - in: query
        name: offset
        schema:
          type: integer
        description: Skip this many rows first. Not accepted together with a row id.
      - in: query
        name: orderby
        schema:
          type: string
        description: Sort by this column. Not accepted together with a row id.
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      - in: query
        name: where
        schema:
          type: string
        description: A filter, as `column=value`, `column>value`, `column<value` or
          the negated forms. Repeat the parameter to apply several. Not accepted together
          with a row id in the path -- the id already names the row.
      tags:
      - schema
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The rows, as a list of objects keyed by column name.
      deprecated: true
    post:
      operationId: schema_[\w\d_]_tables_rows_new_create
      description: |-
        At `rows/new` this inserts and answers `201`. At `rows/<id>` it updates that row, and at `rows/` it updates the rows a filter selects.

        The payload sits under a `query` key rather than at the top level.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/rows/new` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Insert or update rows
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Row'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Row'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Row'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: The rows as they now stand.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Inserted.
      deprecated: true
    put:
      operationId: schema_[\w\d_]_tables_rows_new_update
      description: |-
        Updates the row at this id, or inserts it there if it is not yet taken. **An id never changes**: an `id` in the payload that disagrees with the one in the address is a `409` rather than a move. Requires an id -- `rows/new` is a `POST`.

        The payload sits under a `query` key rather than at the top level.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/rows/new` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Put one row at an id
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: row_id
        schema:
          type: integer
        description: The row's id.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Row'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Row'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Row'
        required: true
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '409':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: A table of that name already exists. Table names are global.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Updated.
        '201':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Inserted at that id.
      deprecated: true
    delete:
      operationId: schema_[\w\d_]_tables_rows_new_destroy
      description: |-
        One row by id, or the rows a `where` filter selects. Deleting with neither deletes every row in the table.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/rows/new` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Delete rows
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: query
        name: column
        schema:
          type: string
        description: Return only this column. Repeat the parameter for several. Each
          must be a Postgres identifier; anything else is refused rather than ignored.
      - in: query
        name: form
        schema:
          type: string
        description: '`csv` returns the rows as CSV instead of JSON.'
      - in: query
        name: limit
        schema:
          type: integer
        description: At most this many rows. Not accepted together with a row id.
      - in: query
        name: offset
        schema:
          type: integer
        description: Skip this many rows first. Not accepted together with a row id.
      - in: query
        name: orderby
        schema:
          type: string
        description: Sort by this column. Not accepted together with a row id.
      - in: path
        name: row_id
        schema:
          type: integer
        description: One row's id. Omit it to address the whole table; the filter
          parameters are then what select rows.
        required: true
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      - in: query
        name: where
        schema:
          type: string
        description: A filter, as `column=value`, `column>value`, `column<value` or
          the negated forms. Repeat the parameter to apply several. Not accepted together
          with a row id in the path -- the id already names the row.
      tags:
      - schema
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '400':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'The request could not be carried out as sent: a payload key
            missing or holding something this endpoint cannot use, a column name that
            is not a Postgres identifier, or a query the database refused. The body
            carries `reason` or `error` naming which.'
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: What was deleted.
      deprecated: true
  /api/v0/schema/{schema}/tables/{table}/unpublish:
    post:
      operationId: schema_[\w\d_]_tables_unpublish_create
      description: |-
        Marks the table not published. It keeps its topic and its rows; what changes is whether it is listed. Needs administrator permission on the table.

        **Deprecated.** This is the older, schema-qualified spelling of the same endpoint. Use `/api/v0/tables/{table}/unpublish` instead: it reaches the same view, and the `{schema}` segment here selects nothing.
      summary: Unpublish a table
      parameters:
      - in: path
        name: schema
        required: true
        schema:
          type: string
        description: '**Ignored.** This segment is not captured by the route, so no
          value of it changes where the request goes: table names are global on this
          platform and the table is found by name alone. It is here because the address
          requires a segment, not because it selects anything.'
      - in: path
        name: table
        schema:
          type: string
        description: 'The table''s name on this platform. **Names are global**: a
          table is addressed by name alone and no two tables share one, whichever
          topic they are published under.'
        required: true
      tags:
      - schema
      security:
      - basicAuth: []
      - cookieAuth: []
      - tokenAuth: []
      - {}
      responses:
        '401':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No credentials, or credentials this platform does not know.
        '403':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: 'Authenticated, but not permitted: the table belongs to somebody
            else, or is under embargo, or the operation needs a level of permission
            on it that this account does not hold.'
        '404':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: No table of that name on this platform.
        '200':
          content:
            application/json:
              schema:
                type: object
                additionalProperties: {}
          description: Unpublished. The body is empty.
      deprecated: true
components:
  schemas:
    AdvancedRequest:
      type: object
      description: |-
        The envelope every `advanced/` endpoint takes.

        `query` is the action's own payload and its keys differ per endpoint --
        `{"table": ...}` for `has_table`, a where-clause structure for `search`.
        It is read leniently: an object, a JSON **string** holding one, or a
        one-element list holding either. That is not a design, it is what
        `_internal_execute` accepts, and a client sending the object is doing the
        plain thing.

        The two identifiers are how a sequence of calls shares one database
        session: `connection/open` hands back a `connection_id`, `cursor/open` a
        `cursor_id`, and passing them here puts this call inside that transaction.
        Without them the call runs on its own and commits by itself.
      properties:
        query:
          description: This endpoint's own payload. See its description.
        connection_id:
          type: string
          description: From `advanced/connection/open`.
        cursor_id:
          type: string
          description: From `advanced/cursor/open`.
    AdvancedResponse:
      type: object
      description: |-
        What every `advanced/` endpoint answers with.

        The result is under `content`, always -- the endpoints differ in what they
        put there, not in where. The two identifiers come back when the call ran
        inside a session, so a client can thread the next call onto the same one.
      properties:
        content:
          description: The action's result. Its shape is the action's own.
        connection_id:
          type: string
        cursor_id:
          type: string
      required:
      - content
    BundleHistoryEntry:
      type: object
      properties:
        era:
          type: string
          description: Which generation of row this is. Entries written before this
            API existed record no verb and no field-level summary.
        verb:
          type: string
          nullable: true
        actor:
          type: string
          nullable: true
          description: A username, not an internal identifier.
        timestamp:
          type: string
          format: date-time
        resource:
          allOf:
          - $ref: '#/components/schemas/ResourceReference'
          description: The class and identifier the write was about.
        acronym:
          type: string
          nullable: true
          description: 'Set on a whole-bundle delete and nowhere else: after that
            write there is no bundle left to read an acronym off, so the line carries
            it.'
        version_before:
          type: integer
          nullable: true
        version_after:
          type: integer
          nullable: true
        changes:
          type: array
          items:
            $ref: '#/components/schemas/HistoryChange'
          nullable: true
          description: '`null` rather than `[]` where there cannot be a summary --
            an empty list would say that nothing changed, and what is known is that
            nothing recorded *what* changed.'
        triples:
          type: object
          additionalProperties: {}
      required:
      - acronym
      - actor
      - changes
      - era
      - resource
      - timestamp
      - verb
      - version_after
      - version_before
    BundleHistoryEntryPage:
      type: object
      properties:
        count:
          type: integer
        next:
          type: string
          format: uri
          nullable: true
        previous:
          type: string
          format: uri
          nullable: true
        results:
          type: array
          items:
            $ref: '#/components/schemas/BundleHistoryEntry'
      required:
      - count
      - next
      - previous
      - results
    BundleMeta:
      type: object
      description: |-
        The two keys that appear only when something was lost after the commit.

        The graph and the relational database cannot share a transaction, and the
        graph commits first. A history entry or an ownership row that could not be
        written afterwards is named beside the success it qualifies rather than
        turned into an error for a write that did happen -- so these are absent on
        an ordinary response and `false` when they are there. Never `true`: a
        client should not have to check something on every response to learn that
        the ordinary thing happened.
      properties:
        history_recorded:
          type: boolean
        ownership_recorded:
          type: boolean
        ownership_forgotten:
          type: boolean
        labels:
          type: object
          additionalProperties:
            type: string
            nullable: true
        uid:
          type: string
        iri:
          type: string
          format: uri
        version:
          type: integer
      required:
      - iri
      - uid
      - version
    BundleRemoval:
      type: object
      properties:
        deleted:
          type: array
          items:
            $ref: '#/components/schemas/RemovedNode'
        unlinked:
          type: array
          items:
            $ref: '#/components/schemas/RemovedNode'
        _meta:
          allOf:
          - $ref: '#/components/schemas/BundleRemovalMeta'
          title: ' meta'
      required:
      - _meta
      - deleted
      - unlinked
    BundleRemovalMeta:
      type: object
      description: |-
        The two keys that appear only when something was lost after the commit.

        The graph and the relational database cannot share a transaction, and the
        graph commits first. A history entry or an ownership row that could not be
        written afterwards is named beside the success it qualifies rather than
        turned into an error for a write that did happen -- so these are absent on
        an ordinary response and `false` when they are there. Never `true`: a
        client should not have to check something on every response to learn that
        the ordinary thing happened.
      properties:
        history_recorded:
          type: boolean
        ownership_recorded:
          type: boolean
        ownership_forgotten:
          type: boolean
        uid:
          type: string
        iri:
          type: string
          format: uri
        acronym:
          type: string
          nullable: true
        version_before:
          type: integer
      required:
      - acronym
      - iri
      - uid
      - version_before
    Dataset:
      type: object
      properties:
        name:
          type: string
          maxLength: 255
        external_url:
          type: string
          format: uri
          nullable: true
          maxLength: 1000
        type:
          $ref: '#/components/schemas/TypeEnum'
      required:
      - name
      - type
    DatasetAssignTables:
      type: object
      properties:
        tables:
          type: array
          items:
            type: object
            additionalProperties:
              type: string
          minItems: 1
      required:
      - tables
    DatasetCreate:
      type: object
      properties:
        name:
          type: string
          description: Name of the dataset
          pattern: ^[-a-zA-Z0-9_]+$
        title:
          type: string
          description: Display name of the dataset, e.g. 'Wind Power Dataset Germany'
        description:
          type: string
          description: Short description of the dataset
        at_id:
          type: string
          format: uri
          description: 'Optional: persistent identifier or URL for the dataset'
      required:
      - description
      - name
      - title
    DatasetLink:
      type: object
      description: |-
        A scenario's link to data on this platform: three keys, all required.

        Not a field table, because a dataset link has no fields of its own: the
        label, the URL and the identifier the shape requires are all derived from
        these three. That is also why there is no partial form of this serializer --
        a link is added or removed, never edited.
      properties:
        type:
          $ref: '#/components/schemas/TypeEnum'
        ref:
          $ref: '#/components/schemas/RefEnum'
        name:
          type: string
      required:
      - name
      - ref
      - type
    DatasetLinkMeta:
      type: object
      description: |-
        The two keys that appear only when something was lost after the commit.

        The graph and the relational database cannot share a transaction, and the
        graph commits first. A history entry or an ownership row that could not be
        written afterwards is named beside the success it qualifies rather than
        turned into an error for a write that did happen -- so these are absent on
        an ordinary response and `false` when they are there. Never `true`: a
        client should not have to check something on every response to learn that
        the ordinary thing happened.
      properties:
        history_recorded:
          type: boolean
        ownership_recorded:
          type: boolean
        ownership_forgotten:
          type: boolean
        labels:
          type: object
          additionalProperties:
            type: string
            nullable: true
        uid:
          type: string
        iri:
          type: string
          format: uri
        type:
          type: string
          format: uri
          description: The OEO class of this resource.
        bundle:
          type: string
        target_iri:
          type: string
          format: uri
          nullable: true
          description: The address actually stored. It is the only thing that stays
            true when `ref` reads `null`, which happens for a link written before
            this API existed that points somewhere this platform has no route for.
        scenario:
          type: string
        resolvable:
          type: boolean
          nullable: true
          description: Whether the named target is still on this platform. `null`
            -- never `false` -- when the stored address is not a page here, because
            `false` would claim the target had been deleted.
        tables:
          type: array
          items:
            $ref: '#/components/schemas/TableEntry'
          nullable: true
          description: 'What the citation means today: the one table for `ref: table`,
            the catalogue entry''s current members for `ref: dataset`, `[]` when the
            named target is gone, and `null` when this server cannot say.'
      required:
      - bundle
      - iri
      - resolvable
      - scenario
      - tables
      - target_iri
      - type
      - uid
    DatasetLinkRead:
      type: object
      description: |-
        A scenario's link to data on this platform: three keys, all required.

        Not a field table, because a dataset link has no fields of its own: the
        label, the URL and the identifier the shape requires are all derived from
        these three. That is also why there is no partial form of this serializer --
        a link is added or removed, never edited.
      properties:
        type:
          $ref: '#/components/schemas/TypeEnum'
        ref:
          $ref: '#/components/schemas/RefEnum'
        name:
          type: string
        _meta:
          allOf:
          - $ref: '#/components/schemas/DatasetLinkMeta'
          title: ' meta'
      required:
      - _meta
      - name
      - ref
      - type
    DatasetLinkReadPage:
      type: object
      properties:
        count:
          type: integer
        next:
          type: string
          format: uri
          nullable: true
        previous:
          type: string
          format: uri
          nullable: true
        results:
          type: array
          items:
            $ref: '#/components/schemas/DatasetLinkRead'
      required:
      - count
      - next
      - previous
      - results
    DatasetRead:
      type: object
      properties:
        uuid:
          type: string
          format: uuid
          readOnly: true
        name:
          type: string
          maxLength: 255
        metadata:
          type: object
          additionalProperties: {}
          readOnly: true
        created_at:
          type: string
          format: date-time
          readOnly: true
      required:
      - created_at
      - metadata
      - name
      - uuid
    DatasetResource:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        schema:
          type: string
          readOnly: true
        name:
          type: string
          maxLength: 1000
        oemetadata:
          nullable: true
        human_readable_name:
          type: string
          nullable: true
          maxLength: 1000
      required:
      - id
      - name
      - schema
    Energyframework:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        model_name:
          type: string
          title: Name
          description: What is the full model name?
          maxLength: 1000
        acronym:
          type: string
          nullable: true
          description: What is the abbreviation?
          maxLength: 20
        url:
          type: string
          readOnly: true
        license:
          allOf:
          - $ref: '#/components/schemas/LicenseEnum'
          description: |-
            Under which license is the framework published?

            * `Academic Free License v3.0` - Academic Free License v3.0
            * `Apache license 2.0` - Apache license 2.0
            * `Artistic license 2.0` - Artistic license 2.0
            * `Boost Software License 1.0` - Boost Software License 1.0
            * `BSD 2-clause "Simplified" license` - BSD 2-clause "Simplified" license
            * `BSD 3-clause Clear license` - BSD 3-clause Clear license
            * `Creative Commons license family` - Creative Commons license family
            * `Creative Commons Zero v1.0 Universal` - Creative Commons Zero v1.0 Universal
            * `Creative Commons Attribution 4.0` - Creative Commons Attribution 4.0
            * `Creative Commons Attribution Share Alike 4.0` - Creative Commons Attribution Share Alike 4.0
            * `Do What The F*ck You Want To Public License` - Do What The F*ck You Want To Public License
            * `Educational Community License v2.0` - Educational Community License v2.0
            * `Eclipse Public License 1.0` - Eclipse Public License 1.0
            * `European Union Public License 1.1` - European Union Public License 1.1
            * `GNU Affero General Public License v3.0` - GNU Affero General Public License v3.0
            * `GNU General Public License family` - GNU General Public License family
            * `GNU General Public License v2.0` - GNU General Public License v2.0
            * `GNU General Public License v3.0` - GNU General Public License v3.0
            * `GNU Lesser General Public License family` - GNU Lesser General Public License family
            * `GNU Lesser General Public License v2.1` - GNU Lesser General Public License v2.1
            * `GNU Lesser General Public License v3.0` - GNU Lesser General Public License v3.0
            * `ISC` - ISC
            * `LaTeX Project Public License v1.3c` - LaTeX Project Public License v1.3c
            * `Microsoft Public License` - Microsoft Public License
            * `MIT` - MIT
            * `Mozilla Public License 2.0` - Mozilla Public License 2.0
            * `Open Software License 3.0` - Open Software License 3.0
            * `PostgreSQL License` - PostgreSQL License
            * `SIL Open Font License 1.1` - SIL Open Font License 1.1
            * `University of Illinois/NCSA Open Source License` - University of Illinois/NCSA Open Source License
            * `The Unlicense` - The Unlicense
            * `zLib License` - zLib License
            * `BSD 3-clause 'New' or 'Revised' license` - BSD 3-clause 'New' or 'Revised' license
            * `Other` - Other
            * `Unknown` - Unknown
        institutions:
          type: array
          items:
            type: string
            maxLength: 1000
          nullable: true
          title: Institution(s)
          description: Which institutions develop(ed) the model?
      required:
      - id
      - model_name
      - url
    Energymodel:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        model_name:
          type: string
          title: Name
          description: What is the full model name?
          maxLength: 1000
        acronym:
          type: string
          nullable: true
          description: What is the abbreviation?
          maxLength: 20
        url:
          type: string
          readOnly: true
        license:
          allOf:
          - $ref: '#/components/schemas/LicenseEnum'
          description: |-
            Under which license is the framework published?

            * `Academic Free License v3.0` - Academic Free License v3.0
            * `Apache license 2.0` - Apache license 2.0
            * `Artistic license 2.0` - Artistic license 2.0
            * `Boost Software License 1.0` - Boost Software License 1.0
            * `BSD 2-clause "Simplified" license` - BSD 2-clause "Simplified" license
            * `BSD 3-clause Clear license` - BSD 3-clause Clear license
            * `Creative Commons license family` - Creative Commons license family
            * `Creative Commons Zero v1.0 Universal` - Creative Commons Zero v1.0 Universal
            * `Creative Commons Attribution 4.0` - Creative Commons Attribution 4.0
            * `Creative Commons Attribution Share Alike 4.0` - Creative Commons Attribution Share Alike 4.0
            * `Do What The F*ck You Want To Public License` - Do What The F*ck You Want To Public License
            * `Educational Community License v2.0` - Educational Community License v2.0
            * `Eclipse Public License 1.0` - Eclipse Public License 1.0
            * `European Union Public License 1.1` - European Union Public License 1.1
            * `GNU Affero General Public License v3.0` - GNU Affero General Public License v3.0
            * `GNU General Public License family` - GNU General Public License family
            * `GNU General Public License v2.0` - GNU General Public License v2.0
            * `GNU General Public License v3.0` - GNU General Public License v3.0
            * `GNU Lesser General Public License family` - GNU Lesser General Public License family
            * `GNU Lesser General Public License v2.1` - GNU Lesser General Public License v2.1
            * `GNU Lesser General Public License v3.0` - GNU Lesser General Public License v3.0
            * `ISC` - ISC
            * `LaTeX Project Public License v1.3c` - LaTeX Project Public License v1.3c
            * `Microsoft Public License` - Microsoft Public License
            * `MIT` - MIT
            * `Mozilla Public License 2.0` - Mozilla Public License 2.0
            * `Open Software License 3.0` - Open Software License 3.0
            * `PostgreSQL License` - PostgreSQL License
            * `SIL Open Font License 1.1` - SIL Open Font License 1.1
            * `University of Illinois/NCSA Open Source License` - University of Illinois/NCSA Open Source License
            * `The Unlicense` - The Unlicense
            * `zLib License` - zLib License
            * `BSD 3-clause 'New' or 'Revised' license` - BSD 3-clause 'New' or 'Revised' license
            * `Other` - Other
            * `Unknown` - Unknown
        institutions:
          type: array
          items:
            type: string
            maxLength: 1000
          nullable: true
          title: Institution(s)
          description: Which institutions develop(ed) the model?
      required:
      - id
      - model_name
      - url
    HistoryChange:
      type: object
      description: One field's worth of a write, rendered at read time from the triples.
      properties:
        field:
          type: string
          nullable: true
          description: '`null` for a triple this cannot attribute to a field -- the
            type and label a minted contact brings with it, say. Reported rather than
            dropped, because dropping it would make the summary look complete when
            it is not.'
        predicate:
          type: string
          format: uri
        removed:
          type: array
          items:
            type: string
        added:
          type: array
          items:
            type: string
      required:
      - added
      - field
      - predicate
      - removed
    LicenseEnum:
      enum:
      - Academic Free License v3.0
      - Apache license 2.0
      - Artistic license 2.0
      - Boost Software License 1.0
      - BSD 2-clause "Simplified" license
      - BSD 3-clause Clear license
      - Creative Commons license family
      - Creative Commons Zero v1.0 Universal
      - Creative Commons Attribution 4.0
      - Creative Commons Attribution Share Alike 4.0
      - Do What The F*ck You Want To Public License
      - Educational Community License v2.0
      - Eclipse Public License 1.0
      - European Union Public License 1.1
      - GNU Affero General Public License v3.0
      - GNU General Public License family
      - GNU General Public License v2.0
      - GNU General Public License v3.0
      - GNU Lesser General Public License family
      - GNU Lesser General Public License v2.1
      - GNU Lesser General Public License v3.0
      - ISC
      - LaTeX Project Public License v1.3c
      - Microsoft Public License
      - MIT
      - Mozilla Public License 2.0
      - Open Software License 3.0
      - PostgreSQL License
      - SIL Open Font License 1.1
      - University of Illinois/NCSA Open Source License
      - The Unlicense
      - zLib License
      - BSD 3-clause 'New' or 'Revised' license
      - Other
      - Unknown
      type: string
      description: |-
        * `Academic Free License v3.0` - Academic Free License v3.0
        * `Apache license 2.0` - Apache license 2.0
        * `Artistic license 2.0` - Artistic license 2.0
        * `Boost Software License 1.0` - Boost Software License 1.0
        * `BSD 2-clause "Simplified" license` - BSD 2-clause "Simplified" license
        * `BSD 3-clause Clear license` - BSD 3-clause Clear license
        * `Creative Commons license family` - Creative Commons license family
        * `Creative Commons Zero v1.0 Universal` - Creative Commons Zero v1.0 Universal
        * `Creative Commons Attribution 4.0` - Creative Commons Attribution 4.0
        * `Creative Commons Attribution Share Alike 4.0` - Creative Commons Attribution Share Alike 4.0
        * `Do What The F*ck You Want To Public License` - Do What The F*ck You Want To Public License
        * `Educational Community License v2.0` - Educational Community License v2.0
        * `Eclipse Public License 1.0` - Eclipse Public License 1.0
        * `European Union Public License 1.1` - European Union Public License 1.1
        * `GNU Affero General Public License v3.0` - GNU Affero General Public License v3.0
        * `GNU General Public License family` - GNU General Public License family
        * `GNU General Public License v2.0` - GNU General Public License v2.0
        * `GNU General Public License v3.0` - GNU General Public License v3.0
        * `GNU Lesser General Public License family` - GNU Lesser General Public License family
        * `GNU Lesser General Public License v2.1` - GNU Lesser General Public License v2.1
        * `GNU Lesser General Public License v3.0` - GNU Lesser General Public License v3.0
        * `ISC` - ISC
        * `LaTeX Project Public License v1.3c` - LaTeX Project Public License v1.3c
        * `Microsoft Public License` - Microsoft Public License
        * `MIT` - MIT
        * `Mozilla Public License 2.0` - Mozilla Public License 2.0
        * `Open Software License 3.0` - Open Software License 3.0
        * `PostgreSQL License` - PostgreSQL License
        * `SIL Open Font License 1.1` - SIL Open Font License 1.1
        * `University of Illinois/NCSA Open Source License` - University of Illinois/NCSA Open Source License
        * `The Unlicense` - The Unlicense
        * `zLib License` - zLib License
        * `BSD 3-clause 'New' or 'Revised' license` - BSD 3-clause 'New' or 'Revised' license
        * `Other` - Other
        * `Unknown` - Unknown
    NodeReference:
      type: object
      description: 'A contact, organisation or funder: referenced by IRI, or minted
        here.'
      properties:
        iri:
          type: string
          nullable: true
        label:
          type: string
      required:
      - label
    NullEnum:
      enum:
      - null
    Part:
      type: object
      description: 'A framework or model factsheet: bundle-local, with a link out.'
      properties:
        label:
          type: string
        iri:
          type: string
          nullable: true
      required:
      - label
    PatchedScenario:
      type: object
      description: |-
        One scenario factsheet -- a sub-resource, not a field of its bundle.

        What makes it one is the shape: it carries its own has-uuid. That uuid is
        **not** a field here, because the server mints it; a client supplies no
        identifier anywhere in this API.
      properties:
        label:
          type: string
        acronym:
          type: string
        abstract:
          type: string
          nullable: true
        study_regions:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        interacting_regions:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        years:
          type: array
          items:
            type: string
            format: date-time
        scenario_types:
          type: array
          items:
            type: string
    PatchedScenarioBundle:
      type: object
      description: The closed bundle field set -- these and nothing else.
      properties:
        label:
          type: string
        acronym:
          type: string
        abstract:
          type: string
          nullable: true
        contacts:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        organisations:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        funders:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        frameworks:
          type: array
          items:
            $ref: '#/components/schemas/Part'
        models:
          type: array
          items:
            $ref: '#/components/schemas/Part'
        descriptors:
          type: array
          items:
            type: string
        sector_divisions:
          type: array
          items:
            type: string
        sectors:
          type: array
          items:
            type: string
        technologies:
          type: array
          items:
            type: string
        energy_carriers:
          type: array
          items:
            type: string
    PatchedStudyReport:
      type: object
      description: |-
        One study report -- the publication a bundle is written up in.

        A sub-resource for the same reason a scenario is: the shape gives it its
        own has-uuid, which the server mints, so it is not a field here.

        What the shape requires of one, and therefore what is required here: a
        label, at least one author, and exactly one publication date. The doi and
        the reference are optional, and the reference is singular because the shape
        allows at most one.
      properties:
        label:
          type: string
        doi:
          type: string
          nullable: true
        publication_date:
          type: string
          format: date-time
        authors:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        reference:
          type: string
          format: uri
          nullable: true
    PeerReviewEnum:
      enum:
      - finished
      - in_progress
      type: string
      description: |-
        * `finished` - finished
        * `in_progress` - in_progress
    QueryWrapped:
      type: object
      description: A payload this endpoint reads out of a `query` key.
      properties:
        query: {}
      required:
      - query
    RefEnum:
      enum:
      - table
      - dataset
      type: string
      description: |-
        * `table` - table
        * `dataset` - dataset
    Removal:
      type: object
      description: |-
        What a delete came to: two lists, because one status code cannot say.

        `unlinked` holds only the nodes the typed containment walk **downgraded** --
        ones something outside this bundle still cites, so they were detached
        rather than destroyed. The shared regions, authors and ontology terms every
        delete detaches are the rule that always applies, and listing them would
        bury the line that is news.
      properties:
        deleted:
          type: array
          items:
            $ref: '#/components/schemas/RemovedNode'
        unlinked:
          type: array
          items:
            $ref: '#/components/schemas/RemovedNode'
        _meta:
          allOf:
          - $ref: '#/components/schemas/RemovalMeta'
          title: ' meta'
      required:
      - _meta
      - deleted
      - unlinked
    RemovalMeta:
      type: object
      description: |-
        The two keys that appear only when something was lost after the commit.

        The graph and the relational database cannot share a transaction, and the
        graph commits first. A history entry or an ownership row that could not be
        written afterwards is named beside the success it qualifies rather than
        turned into an error for a write that did happen -- so these are absent on
        an ordinary response and `false` when they are there. Never `true`: a
        client should not have to check something on every response to learn that
        the ordinary thing happened.
      properties:
        history_recorded:
          type: boolean
        ownership_recorded:
          type: boolean
        ownership_forgotten:
          type: boolean
        bundle:
          type: string
        resource:
          $ref: '#/components/schemas/ResourceReference'
        scenario:
          type: string
      required:
      - bundle
      - resource
    RemovedNode:
      type: object
      description: 'A node as a delete reports it back: an address and a class.'
      properties:
        iri:
          type: string
          format: uri
        type:
          type: string
          format: uri
          nullable: true
          description: '`null` for a node whose class this API does not recognise,
            which a response listing a bare address would not have said.'
      required:
      - iri
      - type
    ResourceReference:
      type: object
      description: |-
        Which resource a line is about: its OEO class and its identifier.

        Both nullable, and for one reason: a row written before sub-resources
        existed names neither, and is read as a bundle write.
      properties:
        type:
          type: string
          format: uri
          nullable: true
        uid:
          type: string
          nullable: true
      required:
      - type
      - uid
    Row:
      type: object
      description: |-
        One row, or the values to set on the rows a filter selects.

        Column names are the keys of `query`. On a `PUT` an `id` in the payload
        must match the one in the path if it is sent at all: an id never changes.
      properties:
        connection_id:
          type: string
          description: From `advanced/connection/open`.
        cursor_id:
          type: string
          description: From `advanced/cursor/open`.
        query: {}
      required:
      - query
    Scenario:
      type: object
      description: |-
        One scenario factsheet -- a sub-resource, not a field of its bundle.

        What makes it one is the shape: it carries its own has-uuid. That uuid is
        **not** a field here, because the server mints it; a client supplies no
        identifier anywhere in this API.
      properties:
        label:
          type: string
        acronym:
          type: string
        abstract:
          type: string
          nullable: true
        study_regions:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        interacting_regions:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        years:
          type: array
          items:
            type: string
            format: date-time
        scenario_types:
          type: array
          items:
            type: string
      required:
      - acronym
      - label
    ScenarioBundleCreate:
      type: object
      description: |-
        The bundle field set **plus** its nested sub-resources, for `POST` only.

        The asymmetry is the whole point and it is structural rather than a flag: a
        bundle `POST` builds its scenarios and study reports with it, and a bundle
        `PATCH` uses the class above, which has no such key and therefore refuses
        one. That is what lets a pipeline create a whole bundle in one call without
        giving any call the power to drop its parts by omitting them.

        Dataset links are deliberately **not** here. They hang off a scenario
        rather than off the bundle, and they are add-and-remove only, so there is
        no partial update of one to reason about -- nesting them would make a
        create the one place their fields could be written together.
      properties:
        label:
          type: string
        acronym:
          type: string
        abstract:
          type: string
          nullable: true
        contacts:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        organisations:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        funders:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        frameworks:
          type: array
          items:
            $ref: '#/components/schemas/Part'
        models:
          type: array
          items:
            $ref: '#/components/schemas/Part'
        scenarios:
          type: array
          items:
            $ref: '#/components/schemas/Scenario'
        study_reports:
          type: array
          items:
            $ref: '#/components/schemas/StudyReport'
        descriptors:
          type: array
          items:
            type: string
        sector_divisions:
          type: array
          items:
            type: string
        sectors:
          type: array
          items:
            type: string
        technologies:
          type: array
          items:
            type: string
        energy_carriers:
          type: array
          items:
            type: string
      required:
      - acronym
      - label
    ScenarioBundleRead:
      type: object
      description: The bundle, its parts nested, exactly as a `POST` would take it
        back.
      properties:
        label:
          type: string
        acronym:
          type: string
        abstract:
          type: string
          nullable: true
        contacts:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        organisations:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        funders:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        frameworks:
          type: array
          items:
            $ref: '#/components/schemas/Part'
        models:
          type: array
          items:
            $ref: '#/components/schemas/Part'
        scenarios:
          type: array
          items:
            $ref: '#/components/schemas/ScenarioRead'
        study_reports:
          type: array
          items:
            $ref: '#/components/schemas/StudyReportRead'
        _meta:
          allOf:
          - $ref: '#/components/schemas/BundleMeta'
          title: ' meta'
        descriptors:
          type: array
          items:
            type: string
        sector_divisions:
          type: array
          items:
            type: string
        sectors:
          type: array
          items:
            type: string
        technologies:
          type: array
          items:
            type: string
        energy_carriers:
          type: array
          items:
            type: string
      required:
      - _meta
      - acronym
      - label
      - scenarios
      - study_reports
    ScenarioBundleScenarioDataset:
      type: object
      properties:
        scenario_bundle:
          type: string
          format: uuid
        scenario:
          type: string
          format: uuid
        datasets:
          type: array
          items:
            $ref: '#/components/schemas/Dataset'
      required:
      - datasets
      - scenario
      - scenario_bundle
    ScenarioBundleSummary:
      type: object
      description: |-
        Enough to find a bundle and decide which one, and nothing else.

        Not a bundle with fields left out: the two a human recognises a bundle by
        stay at the top level, where a bundle read has them too, and everything a
        client cannot write is in `_meta`. The version is there because it is what
        a pipeline's next write must send.
      properties:
        label:
          type: string
          nullable: true
        acronym:
          type: string
          nullable: true
        _meta:
          allOf:
          - $ref: '#/components/schemas/SummaryMeta'
          title: ' meta'
      required:
      - _meta
      - acronym
      - label
    ScenarioBundleSummaryPage:
      type: object
      properties:
        count:
          type: integer
        next:
          type: string
          format: uri
          nullable: true
        previous:
          type: string
          format: uri
          nullable: true
        results:
          type: array
          items:
            $ref: '#/components/schemas/ScenarioBundleSummary'
      required:
      - count
      - next
      - previous
      - results
    ScenarioDataTables:
      type: object
      properties:
        id:
          type: integer
          readOnly: true
        name:
          type: string
          maxLength: 1000
        human_readable_name:
          type: string
          nullable: true
          maxLength: 1000
        url:
          type: string
          readOnly: true
      required:
      - id
      - name
      - url
    ScenarioRead:
      type: object
      description: |-
        One scenario factsheet -- a sub-resource, not a field of its bundle.

        What makes it one is the shape: it carries its own has-uuid. That uuid is
        **not** a field here, because the server mints it; a client supplies no
        identifier anywhere in this API.
      properties:
        label:
          type: string
        acronym:
          type: string
        abstract:
          type: string
          nullable: true
        study_regions:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        interacting_regions:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        years:
          type: array
          items:
            type: string
            format: date-time
        _meta:
          allOf:
          - $ref: '#/components/schemas/SubResourceMeta'
          title: ' meta'
        scenario_types:
          type: array
          items:
            type: string
      required:
      - _meta
      - acronym
      - label
    ScenarioReadPage:
      type: object
      properties:
        count:
          type: integer
        next:
          type: string
          format: uri
          nullable: true
        previous:
          type: string
          format: uri
          nullable: true
        results:
          type: array
          items:
            $ref: '#/components/schemas/ScenarioRead'
      required:
      - count
      - next
      - previous
      - results
    Sparql:
      type: object
      description: A read-only SPARQL query against the OEKG.
      properties:
        query:
          type: string
          description: The query. **Reads only** -- anything that would update or
            delete is refused, whatever the caller's permissions.
        format:
          type: string
          description: The result format the graph store should use. Defaults to `json`;
            anything else is returned with the store's own content type rather than
            parsed.
      required:
      - query
    StudyReport:
      type: object
      description: |-
        One study report -- the publication a bundle is written up in.

        A sub-resource for the same reason a scenario is: the shape gives it its
        own has-uuid, which the server mints, so it is not a field here.

        What the shape requires of one, and therefore what is required here: a
        label, at least one author, and exactly one publication date. The doi and
        the reference are optional, and the reference is singular because the shape
        allows at most one.
      properties:
        label:
          type: string
        doi:
          type: string
          nullable: true
        publication_date:
          type: string
          format: date-time
        authors:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        reference:
          type: string
          format: uri
          nullable: true
      required:
      - authors
      - label
      - publication_date
    StudyReportRead:
      type: object
      description: |-
        One study report -- the publication a bundle is written up in.

        A sub-resource for the same reason a scenario is: the shape gives it its
        own has-uuid, which the server mints, so it is not a field here.

        What the shape requires of one, and therefore what is required here: a
        label, at least one author, and exactly one publication date. The doi and
        the reference are optional, and the reference is singular because the shape
        allows at most one.
      properties:
        label:
          type: string
        doi:
          type: string
          nullable: true
        publication_date:
          type: string
          format: date-time
        authors:
          type: array
          items:
            $ref: '#/components/schemas/NodeReference'
        reference:
          type: string
          format: uri
          nullable: true
        _meta:
          allOf:
          - $ref: '#/components/schemas/SubResourceMeta'
          title: ' meta'
      required:
      - _meta
      - authors
      - label
      - publication_date
    StudyReportReadPage:
      type: object
      properties:
        count:
          type: integer
        next:
          type: string
          format: uri
          nullable: true
        previous:
          type: string
          format: uri
          nullable: true
        results:
          type: array
          items:
            $ref: '#/components/schemas/StudyReportRead'
      required:
      - count
      - next
      - previous
      - results
    SubResourceMeta:
      type: object
      description: |-
        The two keys that appear only when something was lost after the commit.

        The graph and the relational database cannot share a transaction, and the
        graph commits first. A history entry or an ownership row that could not be
        written afterwards is named beside the success it qualifies rather than
        turned into an error for a write that did happen -- so these are absent on
        an ordinary response and `false` when they are there. Never `true`: a
        client should not have to check something on every response to learn that
        the ordinary thing happened.
      properties:
        history_recorded:
          type: boolean
        ownership_recorded:
          type: boolean
        ownership_forgotten:
          type: boolean
        labels:
          type: object
          additionalProperties:
            type: string
            nullable: true
        uid:
          type: string
        iri:
          type: string
          format: uri
        type:
          type: string
          format: uri
          description: The OEO class of this resource.
        bundle:
          type: string
      required:
      - bundle
      - iri
      - type
      - uid
    SummaryCounts:
      type: object
      properties:
        scenarios:
          type: integer
        study_reports:
          type: integer
      required:
      - scenarios
      - study_reports
    SummaryMeta:
      type: object
      properties:
        uid:
          type: string
        iri:
          type: string
          format: uri
        version:
          type: integer
        counts:
          $ref: '#/components/schemas/SummaryCounts'
      required:
      - counts
      - iri
      - uid
      - version
    TableAlter:
      type: object
      description: |-
        The body of a change to an existing table's columns or constraints.

        Top level, not under `query` -- unlike the create on the same URL, which
        is the kind of thing only a description can warn about.
      properties:
        type:
          type: string
          description: '`column` or `constraint`: which kind of change this is.'
        action:
          type: string
          description: '`ADD` or `DROP`, for a constraint change.'
        name:
          type: string
          description: For a column change.
        constraint_type:
          type: string
          description: '`FOREIGN KEY`, `PRIMARY KEY`, `UNIQUE` or `CHECK`.'
        constraint_name:
          type: string
        constraint_parameter:
          type: string
          description: What the constraint applies to -- a column name.
        reference_table:
          type: string
        reference_column:
          type: string
      required:
      - type
    TableCreate:
      type: object
      description: |-
        The body of a table create: columns, constraints and metadata.

        Under `query`, and the reason is historical rather than principled -- the
        same wrapper the `advanced/` endpoints use, kept here because clients send
        it.
      properties:
        query:
          description: '`columns` (required) is a list of `{name, data_type, is_nullable,
            ...}`; `constraints` is a list of constraint definitions; `metadata` is
            an OEMetadata document. Without `metadata` a minimal one is generated
            from the columns.'
        embargo:
          description: An embargo to apply once the table exists. Also accepted inside
            `query`.
      required:
      - query
    TableEntry:
      type: object
      description: One table a dataset link resolves to, as it stands today.
      properties:
        name:
          type: string
        peer_review:
          nullable: true
          description: |-
            Three-valued, and `null` rather than `false` where there is no review: the peer review process postdates most of the data on this platform, so a boolean would read as a quality judgement on links that predate it. A table with several reviews reads `finished` if any of them finished.

            * `finished` - finished
            * `in_progress` - in_progress
          oneOf:
          - $ref: '#/components/schemas/PeerReviewEnum'
          - $ref: '#/components/schemas/NullEnum'
      required:
      - name
      - peer_review
    TypeEnum:
      enum:
      - input
      - output
      type: string
      description: |-
        * `input` - input
        * `output` - output
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
    cookieAuth:
      type: apiKey
      in: cookie
      name: sessionid
    tokenAuth:
      type: apiKey
      in: header
      name: Authorization
      description: Token-based authentication with required prefix "Token"
