openapi: "3.1.0"
info:
  title: KiDig Partner API
  version: 0.2.0
  description: |
    Public partner API of KiDig-AZ. Endpoints, authentication (OAuth2 client
    registry with facility-side consent grants) and response conventions
    reflect the v1 target state; this environment is staging with demo data.

    Facility data is only accessible after the facility has activated the
    partner connection in KiDig ("grant"). The grant is checked on every
    request — a valid token alone is not sufficient — and every successful
    fetch is recorded in the facility's audit trail with the partner as actor.
  contact:
    name: KiDig
    url: https://www.kidig-online.de
servers:
  - url: https://api-staging.kidig-online.de
    description: Staging (demo)
  - url: https://api.kidig-online.de
    description: Production (partner API not yet enabled here)
paths:
  /v1/oauth/token:
    post:
      operationId: issueToken
      summary: Issue an access token (OAuth2 client credentials)
      tags: [Authentication]
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [grant_type, client_id, client_secret]
              properties:
                grant_type:
                  type: string
                  enum: [client_credentials]
                client_id:
                  type: string
                client_secret:
                  type: string
      responses:
        "200":
          description: Access token issued
          content:
            application/json:
              schema:
                type: object
                properties:
                  access_token:
                    type: string
                  token_type:
                    type: string
                    enum: [Bearer]
                  expires_in:
                    type: integer
                    description: Token lifetime in seconds (currently 1800)
                  scope:
                    type: string
                    example: facility:read
        "400":
          description: Unsupported grant type (RFC 6749 error format)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OAuthError"
        "401":
          description: Unknown client or wrong secret (RFC 6749 error format)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OAuthError"
  /v1/facilities:
    get:
      operationId: listFacilities
      summary: List all facilities with an active grant for this client
      description: >
        Discovery endpoint: returns every facility that currently grants this
        partner access. externalFacilityId is the pairing code the facility
        entered at consent — use it to match the facility to your own records.
        Revoked facilities disappear from this list immediately.
      tags: [Facilities]
      security:
        - oauthClientCredentials: [facility:read]
      parameters:
        - name: If-None-Match
          in: header
          required: false
          schema:
            type: string
      responses:
        "200":
          description: Granted facilities
          headers:
            ETag:
              schema:
                type: string
            X-Request-Id:
              $ref: "#/components/headers/XRequestId"
          content:
            application/json:
              schema:
                type: object
                properties:
                  facilities:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        name:
                          type: string
                        externalFacilityId:
                          type: [string, "null"]
                          description: Pairing code entered by the facility at consent
                        grantedAt:
                          type: string
                          format: date-time
        "304":
          description: Not modified (If-None-Match matched)
        "401":
          description: Missing, invalid or expired access token
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
  /v1/facilities/{facilityId}:
    get:
      operationId: getFacility
      summary: Fetch facility main data
      tags: [Facilities]
      security:
        - oauthClientCredentials: [facility:read]
      parameters:
        - name: facilityId
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: If-None-Match
          in: header
          required: false
          description: >
            ETag from a previous response. If the resource is unchanged the
            server answers 304 without a body — intended for nightly polling.
          schema:
            type: string
      responses:
        "200":
          description: Facility main data
          headers:
            ETag:
              description: Entity tag of the current representation
              schema:
                type: string
            X-Request-Id:
              $ref: "#/components/headers/XRequestId"
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Facility"
        "304":
          description: Not modified (If-None-Match matched)
        "400":
          description: facilityId is not a UUID
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
        "401":
          description: Missing, invalid or expired access token
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
        "403":
          description: No active grant for this facility, or missing scope
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
        "404":
          description: Facility does not exist
          content:
            application/problem+json:
              schema:
                $ref: "#/components/schemas/Problem"
components:
  securitySchemes:
    oauthClientCredentials:
      type: oauth2
      description: >
        Access tokens are JWTs issued by POST /v1/oauth/token and sent as
        "Authorization: Bearer <token>".
      flows:
        clientCredentials:
          tokenUrl: /v1/oauth/token
          scopes:
            facility:read: Read facility master data
  headers:
    XRequestId:
      description: >
        Unique id of this request. Please quote it in support enquiries.
      schema:
        type: string
        format: uuid
  schemas:
    Facility:
      type: object
      properties:
        id:
          type: string
          format: uuid
        name:
          type: string
        address:
          type: object
          properties:
            street:
              type: [string, "null"]
              description: Street and house number
            zipCode:
              type: [string, "null"]
            town:
              type: [string, "null"]
        country:
          type: [string, "null"]
          description: ISO 3166-1 alpha-2, e.g. DE
        federalState:
          type: [string, "null"]
          description: >
            German federal state code, e.g. BW. Public holidays are computed
            by KiDig from country and federal state — partners must not
            derive or send holidays themselves.
    Problem:
      type: object
      description: RFC 7807 problem details
      properties:
        type:
          type: string
          format: uri
          description: Problem type identifier
        title:
          type: string
        status:
          type: integer
        detail:
          type: string
        requestId:
          type: string
          format: uuid
          description: Matches the X-Request-Id response header
    OAuthError:
      type: object
      properties:
        error:
          type: string
          enum: [invalid_client, unsupported_grant_type]
