> ## 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.

# Restore revoked key



## OpenAPI

````yaml /openapi/stand-alone/v3.yaml patch /api/v3/kms/{uuid}/restore
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/kms/{uuid}/restore:
    parameters:
      - $ref: '#/components/parameters/KeyUuid'
    patch:
      tags:
        - KMS
        - STAND
      summary: Restore revoked key
      operationId: restoreKmsKey
      responses:
        '200':
          description: Restored to active.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/KmsKey'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
components:
  parameters:
    KeyUuid:
      name: uuid
      in: path
      required: true
      description: The key's `key_id`.
      schema:
        type: string
        format: uuid
  schemas:
    KmsKey:
      allOf:
        - $ref: '#/components/schemas/KmsKeyBrief'
        - type: object
          required:
            - private_material_retrievable
            - usage_mask
            - updated_at
          properties:
            private_material_retrievable:
              type: boolean
              description: >
                Whether the private half may ever leave this service. Fixed at

                creation: it can be withdrawn later but never granted, because
                the

                guarantee made when the key was generated has to keep holding.
            usage_mask:
              type: array
              items:
                type: string
                enum:
                  - encrypt
                  - decrypt
                  - sign
                  - verify
            classification_id:
              type: string
              format: uuid
            revoke_reason:
              type: string
            rotated_from:
              type: string
              format: uuid
              description: The key this one replaced, when it came from a rotation.
            export_window_expires_at:
              type:
                - string
                - 'null'
              format: date-time
              description: >
                After this, export is refused even for an exportable key.
                Present

                only on exportable keys.
            export_count:
              type: integer
              description: How many times the private half has been exported.
            public_key_pem:
              type: string
              description: RSA keys only.
            private_key_material:
              type: object
              description: |
                Present only in the response to an export, or to a create with
                `export_on_create`. Never returned by a plain fetch.
              required:
                - jwe
              properties:
                jwe:
                  type: string
                  description: >
                    RFC 7516 compact serialisation, `RSA-OAEP-256` with
                    `A256GCM`,

                    wrapped to the named wrap key.
            updated_at:
              type: string
              format: date-time
    KmsKeyBrief:
      type: object
      required:
        - key_id
        - type
        - algorithm
        - state
        - created_at
      properties:
        key_id:
          type: string
          format: uuid
        name:
          type:
            - string
            - 'null'
        external_id:
          type:
            - string
            - 'null'
          description: A caller's own identifier, for reconciling against another system.
        type:
          type: string
          enum:
            - AES
            - RSA
        algorithm:
          type: string
          description: |
            Named as the v3 API this service replaces names it: the key length
            without the cipher mode.
          examples:
            - AES-256
            - RSA-2048
        cipher_mode:
          type: string
          enum:
            - gcm
            - cbc
          description: >
            Absent for RSA. This service tracks the mode per key and the v3 API

            does not, so it is reported here rather than folded into
            `algorithm`.
        state:
          $ref: '#/components/schemas/KeyState'
        created_at:
          type: string
          format: date-time
    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
    KeyState:
      type: string
      enum:
        - active
        - revoked
  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'
    Conflict:
      description: The request conflicts with the current state of the resource.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  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.

````