> ## Documentation Index
> Fetch the complete documentation index at: https://docs.qanapi.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Update API Key Configurations

> Replaces the whole set. Sending an empty list detaches the key from
everything, which stops it reaching data without revoking it.

Requires `apikey:manage` even on your own key, because widening what a
credential reaches is a management action. Every id is verified before
anything is written, so a request naming one bad id does not
half-apply. The change takes effect immediately across the cluster.




## OpenAPI

````yaml /openapi/stand-alone/v3.yaml patch /api/v3/api-keys/{id}/configurations
openapi: 3.1.0
info:
  title: Qanapi Standalone API
  version: 3.0.0
  summary: Single-tenant encryption, key management, classification and audit service.
  description: >
    A standalone cryptographic service. Callers hand it data and it returns

    ciphertext, or hand it ciphertext and it returns data, with every operation

    authorised by policy and recorded on a tamper-evident audit trail.


    ## Authentication


    Two credentials reach the same principal:


    - **API key** in `X-Qanapi-Authorization`, for machine callers. A key
    reaches
      only the configurations it is linked to.
    - **User bearer token** in `Authorization`, from `POST /api/v3/auth/login`,
      for a person working through a console.

    An API key outranks a bearer token when a request carries both, because a

    key names a narrower credential than the user that owns it.


    ## Status codes


    The credential failures are worth stating plainly, because they are not what

    a reader would guess and clients branch on them:


    | Situation | Status |

    |---|---|

    | No credential presented at all | `400` |

    | A credential that does not verify | `401` |

    | A revoked API key | `403` |

    | Authenticated but not permitted | `403` |

    | Request body or parameter is invalid | `422` |


    All of these match the Laravel v3 API this service replaces. Every error
    body

    carries `message` and `error`; validation failures additionally carry a

    field-keyed `errors` object.


    ## Rate limiting


    Every response carries `X-RateLimit-Limit` and `X-RateLimit-Remaining`. The

    window is per node and keyed on the client address, so a cluster of n nodes

    admits n times the configured figure.
  license:
    name: Proprietary
    identifier: LicenseRef-Qanapi-Commercial
servers:
  - url: https://{host}
    description: A deployed instance, behind the reverse proxy that terminates TLS.
    variables:
      host:
        default: qanapi.example.com
  - url: http://localhost:8000
    description: The local Compose cluster, through its load balancer.
security:
  - ApiKeyAuth: []
  - BearerAuth: []
tags:
  - name: STAND
    description: |
      Every operation this service serves. Carried on all of them so the
      standalone surface can be selected as a whole, which matters where this
      description is rendered or merged alongside another Qanapi API.

      It is a marker rather than a grouping: each operation keeps the tag that
      says what it does, and that one is listed first.
  - name: Health
    description: |
      Liveness and readiness probes. Registered outside the authentication,
      audit and transport layers, so a load balancer polling them without
      credentials still gets an answer.
  - name: Authentication
    description: Logging in, and creating the first administrator.
  - name: Users
    description: User accounts and their roles.
  - name: API keys
    description: >
      Machine credentials. A key is scoped to a set of configurations and
      reaches

      nothing until it is linked to at least one.
  - name: Configurations
    description: >
      Encryption configurations, called configurations on the wire for
      compatibility

      with the v3 API this service replaces. A configuration owns a master key
      and is

      the unit of cryptographic isolation.
  - name: Classifications
    description: |
      Sensitivity labels and the clearance that reaches them.
  - name: Policies
    description: Allow and deny rules binding a principal to actions on resources.
  - name: Encryption
    description: >
      The data plane. Field-level or whole-body encryption under a
      configuration,

      optionally forwarded onward to a destination of the caller's choosing.
  - name: KMS
    description: Customer-managed key lifecycle, import and export.
  - name: Audit
    description: The tamper-evident record of everything the service did.
  - name: Transport
    description: The service's own key pair, for end-to-end encrypted request bodies.
paths:
  /api/v3/api-keys/{id}/configurations:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    patch:
      tags:
        - API keys
        - STAND
      summary: Update API Key Configurations
      description: |
        Replaces the whole set. Sending an empty list detaches the key from
        everything, which stops it reaching data without revoking it.

        Requires `apikey:manage` even on your own key, because widening what a
        credential reaches is a management action. Every id is verified before
        anything is written, so a request naming one bad id does not
        half-apply. The change takes effect immediately across the cluster.
      operationId: setApiKeyConfigurations
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SetApiKeyContainersRequest'
      responses:
        '200':
          description: The key, with its new configuration set.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKey'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          description: |
            Concurrent writes to the same key could not be serialised. The write
            is sound; retry it.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          $ref: '#/components/responses/ValidationFailed'
components:
  parameters:
    ResourceId:
      name: id
      in: path
      required: true
      schema:
        type: string
        format: uuid
  schemas:
    SetApiKeyContainersRequest:
      type: object
      required:
        - configuration_ids
      properties:
        configuration_ids:
          type: array
          description: The complete new set. An empty array detaches everything.
          items:
            type: string
            format: uuid
    ApiKey:
      type: object
      required:
        - id
        - user_id
        - name
        - prefix
        - created_at
      properties:
        id:
          type: string
          format: uuid
        user_id:
          type: string
          format: uuid
          description: |
            The owning user. Classification clearance for this key resolves
            through this user and their role.
        name:
          type: string
        prefix:
          type: string
          description: The indexed first twelve characters.
          examples:
            - qk_TEcj6-ebd
        revoked_at:
          type:
            - string
            - 'null'
          format: date-time
        last_used_at:
          type:
            - string
            - 'null'
          format: date-time
        created_at:
          type: string
          format: date-time
        configurations:
          type: array
          description: |
            The configurations this key may reach. An empty list means none: the
            grant is explicit, so a newly minted key cannot touch data until
            somebody says which data it is for.
          items:
            type: object
            required:
              - id
              - name
              - proxy_slug
            properties:
              id:
                type: string
                format: uuid
              name:
                type: string
              proxy_slug:
                type: string
    Error:
      type: object
      required:
        - message
        - error
      properties:
        message:
          type: string
          description: >
            Human readable. A 5xx is described by its category and nothing more:

            operational detail such as a path or a setting name stays in the
            log.
          examples:
            - Unauthorized.
        error:
          type: string
          description: |
            A stable machine readable code. This service sends it and the v3 API
            it replaces does not, which is what lets the two share the same
            `message` strings without losing specificity: `Resource not found.`
            still arrives alongside `KmsKeyNotFoundException`.
          examples:
            - InvalidApiKeyException
    ValidationError:
      allOf:
        - $ref: '#/components/schemas/Error'
        - type: object
          required:
            - errors
          properties:
            errors:
              type: object
              description: >
                Messages keyed by the field they concern. A failure with no
                single

                field to blame is filed under `request`.
              additionalProperties:
                type: array
                items:
                  type: string
              examples:
                - type:
                    - The type field is required.
                  configuration_ids:
                    - No configuration has the id `...`.
  responses:
    Forbidden:
      description: |
        Authenticated, but not permitted. Also returned for a revoked API key.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: No such record.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    ValidationFailed:
      description: |
        The request body or a parameter is invalid. `message` is always
        `Validation failed`; the specifics are in `errors`, keyed by field.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ValidationError'
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-Qanapi-Authorization
      description: >
        A machine credential, `qk_` followed by its secret. The first twelve

        characters are an indexed prefix; the rest is compared in constant time

        against a stored SHA-256 hash. A key reaches only the configurations it
        is

        linked to.


        It may also be sent as `Authorization: Bearer qk_...`, which is

        recognised by the prefix.
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: |
        A user token from `POST /api/v3/auth/login`. The token asserts a role,
        but the database decides it, so a role changed or a user deleted after
        the token was issued takes effect immediately. A token minted before a
        password change is refused.

````