openapi: 3.0.3
info:
  title: Potenzialanalyse API
  description: |
    REST API für HR-Potenzialanalysen - Assessment-Tests für Recruiting und Personalentwicklung.

    ## Authentifizierung
    Alle authentifizierten Endpoints erfordern einen Bearer Token im Authorization Header:
    ```
    Authorization: Bearer pk_live_xxx
    ```

    ## Rate Limiting
    - 100 Requests pro Minute pro API Key
    - Bei Überschreitung: HTTP 429

    ## Workflow
    1. **Produkte ansehen** - `GET /products` (öffentlich)
    2. **Paket kaufen** - `POST /orders` (erzeugt Stripe Checkout)
    3. **Guthaben prüfen** - `GET /balance`
    4. **Kandidat einladen** - `POST /invites`
    5. **Ergebnis abrufen** - `GET /results/{id}`
  version: 1.0.0
  contact:
    email: ralph.koebler@potenzial.at
    url: https://www.potenzial.at
  license:
    name: Proprietary
    url: https://www.potenzial.at/agb/

servers:
  - url: https://www.potenzial.at/api/v1
    description: Production Server

tags:
  - name: Discovery
    description: API discovery and product catalog (public)
  - name: Registration
    description: Self-service API key registration (public)
  - name: Commerce
    description: Orders and payments
  - name: Execution
    description: Invite candidates and get results
  - name: Webhooks
    description: Event notifications

paths:
  /:
    get:
      tags: [Discovery]
      summary: API Information
      description: Returns API metadata and available endpoints
      operationId: getApiInfo
      responses:
        '200':
          description: API information
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiInfo'

  /register:
    post:
      tags: [Registration]
      summary: Register for API Access
      description: |
        Self-service registration for new API customers. Creates a new customer account
        and generates an API key. The key is shown only once in the response - save it immediately!

        Optionally include a product_id to create a Stripe checkout session for purchasing credits.
      operationId: registerApiAccess
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RegisterRequest'
            example:
              email: "developer@example.com"
              company: "Example GmbH"
              name: "Max Mustermann"
              address: "Musterstraße 1"
              zip: "1010"
              city: "Wien"
              country: "AT"
              vat_id: "ATU12345678"
              billing_contact: "Buchhaltung"
              phone: "+43 1 234567"
              website: "https://www.example.at"
              product_id: "pa-pack-10"
              mode: "live"
      responses:
        '201':
          description: Registration successful
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RegisterResponse'
        '400':
          description: Invalid input (missing email or company)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: Email already registered
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /products:
    get:
      tags: [Discovery]
      summary: List Products
      description: Returns available assessment products with pricing (public, no auth required)
      operationId: listProducts
      parameters:
        - name: category
          in: query
          schema:
            type: string
          description: Filter by category
        - name: max_price
          in: query
          schema:
            type: number
          description: Maximum price filter
        - name: min_credits
          in: query
          schema:
            type: integer
          description: Minimum credits filter
      responses:
        '200':
          description: Product list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProductList'

  /orders:
    post:
      tags: [Commerce]
      summary: Create Order
      description: Create a new order and get Stripe checkout URL
      operationId: createOrder
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: Order created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /orders/{orderId}:
    get:
      tags: [Commerce]
      summary: Get Order Status
      description: Check the status of an order
      operationId: getOrder
      security:
        - bearerAuth: []
      parameters:
        - name: orderId
          in: path
          required: true
          schema:
            type: string
          example: ord_abc123xyz
      responses:
        '200':
          description: Order details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderStatus'
        '404':
          $ref: '#/components/responses/NotFound'

  /balance:
    get:
      tags: [Execution]
      summary: Check Balance
      description: Get current credit balance and package details
      operationId: getBalance
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Balance information
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/BalanceResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'

  /invites:
    post:
      tags: [Execution]
      summary: Create Invite
      description: Invite a candidate to take an assessment (consumes 1 credit)
      operationId: createInvite
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateInviteRequest'
      responses:
        '201':
          description: Invite created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InviteResponse'
        '402':
          description: Insufficient credits
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    get:
      tags: [Execution]
      summary: List Invites
      description: List all invites with optional filtering
      operationId: listInvites
      security:
        - bearerAuth: []
      parameters:
        - name: status
          in: query
          schema:
            type: string
            enum: [pending, started, completed, expired]
        - name: limit
          in: query
          schema:
            type: integer
            default: 20
            maximum: 100
        - name: offset
          in: query
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: Invite list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InviteList'

  /invites/{inviteId}:
    get:
      tags: [Execution]
      summary: Get Invite Status
      description: Check the status of a specific invite
      operationId: getInvite
      security:
        - bearerAuth: []
      parameters:
        - name: inviteId
          in: path
          required: true
          schema:
            type: string
          example: inv_abc123xyz
      responses:
        '200':
          description: Invite details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InviteResponse'
        '404':
          $ref: '#/components/responses/NotFound'

  /results/{inviteId}:
    get:
      tags: [Execution]
      summary: Get Results
      description: Retrieve assessment results for a completed invite
      operationId: getResults
      security:
        - bearerAuth: []
      parameters:
        - name: inviteId
          in: path
          required: true
          schema:
            type: string
          example: inv_abc123xyz
        - name: include_raw
          in: query
          schema:
            type: boolean
            default: false
          description: Include raw session data
      responses:
        '200':
          description: Assessment results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResultsResponse'
        '202':
          description: Analysis not yet completed
        '404':
          $ref: '#/components/responses/NotFound'

  /webhooks:
    post:
      tags: [Webhooks]
      summary: Register Webhook
      description: Register a URL to receive event notifications
      operationId: createWebhook
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateWebhookRequest'
      responses:
        '201':
          description: Webhook created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookResponse'
    get:
      tags: [Webhooks]
      summary: List Webhooks
      description: List all registered webhooks
      operationId: listWebhooks
      security:
        - bearerAuth: []
      responses:
        '200':
          description: Webhook list
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookList'

components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: 'Format: pk_live_[32-char-hex]'

  schemas:
    ApiInfo:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            name:
              type: string
            version:
              type: string
            description:
              type: string

    ProductList:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            products:
              type: array
              items:
                $ref: '#/components/schemas/Product'
            total:
              type: integer

    Product:
      type: object
      properties:
        productID:
          type: string
        name:
          type: string
        description:
          type: string
        offers:
          type: object
          properties:
            price:
              type: string
            priceCurrency:
              type: string
        credits:
          type: integer
        features:
          type: array
          items:
            type: string

    CreateOrderRequest:
      type: object
      required:
        - product_id
      properties:
        product_id:
          type: string
          example: pa-pack-10
        email:
          type: string
          format: email

    OrderResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            order_id:
              type: string
            status:
              type: string
            product:
              type: object
            payment:
              type: object
              properties:
                amount:
                  type: number
                currency:
                  type: string
                checkout_url:
                  type: string
                  format: uri

    OrderStatus:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            order_id:
              type: string
            status:
              type: string
              enum: [pending_payment, completed, cancelled]
            payment_status:
              type: string

    BalanceResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            customer:
              type: object
            balance:
              type: object
              properties:
                credits_available:
                  type: integer
                credits_used:
                  type: integer
            packages:
              type: array
              items:
                type: object

    CreateInviteRequest:
      type: object
      required:
        - email
      properties:
        email:
          type: string
          format: email
          description: Candidate's email address
        name:
          type: string
          description: Candidate's name (optional)
        product_type:
          type: string
          default: potenzialanalyse
        send_email:
          type: boolean
          default: true
          description: Send invitation email to candidate

    InviteResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            invite_id:
              type: string
            status:
              type: string
              enum: [pending, started, completed, expired]
            candidate:
              type: object
              properties:
                email:
                  type: string
                name:
                  type: string
            analysis_link:
              type: string
              format: uri
            created_at:
              type: string
              format: date-time

    InviteList:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            invites:
              type: array
              items:
                $ref: '#/components/schemas/InviteResponse'
            total:
              type: integer

    ResultsResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            invite_id:
              type: string
            status:
              type: string
            candidate:
              type: object
            completed_at:
              type: string
              format: date-time
            scores:
              type: object
              additionalProperties:
                type: number
            overall_score:
              type: number
            report:
              type: object
              properties:
                pdf_url:
                  type: string
                  format: uri

    CreateWebhookRequest:
      type: object
      required:
        - url
      properties:
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
            enum: [analysis.completed, analysis.started, order.completed]

    WebhookResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            webhook_id:
              type: string
            url:
              type: string
            secret:
              type: string
              description: HMAC signing secret (shown only once)
            events:
              type: array
              items:
                type: string

    WebhookList:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            webhooks:
              type: array
              items:
                type: object

    RegisterRequest:
      type: object
      required:
        - email
        - company
      properties:
        email:
          type: string
          format: email
          description: Contact email for the API account
        company:
          type: string
          description: Company or organization name
        name:
          type: string
          description: Contact person name (optional)
        address:
          type: string
          description: Street address (optional)
          example: "Musterstraße 1"
        zip:
          type: string
          description: Postal/ZIP code (optional)
          example: "1010"
        city:
          type: string
          description: City (optional)
          example: "Wien"
        country:
          type: string
          description: ISO country code (optional, default AT)
          default: "AT"
          example: "AT"
        vat_id:
          type: string
          description: VAT ID for invoicing (optional)
          example: "ATU12345678"
        billing_contact:
          type: string
          description: Billing contact person for invoices (z.Hd.)
          example: "Buchhaltung"
        phone:
          type: string
          description: Contact phone number (optional)
          example: "+43 1 234567"
        website:
          type: string
          format: uri
          description: Company website (optional)
          example: "https://www.example.at"
        product_id:
          type: string
          description: Product ID to purchase immediately (optional)
          enum: [pa-single, pa-pack-10, pa-pack-50]
        mode:
          type: string
          description: API key mode (optional, default live)
          enum: [live, test]
          default: "live"

    RegisterResponse:
      type: object
      properties:
        success:
          type: boolean
        data:
          type: object
          properties:
            message:
              type: string
            customer:
              type: object
              properties:
                id:
                  type: string
                company:
                  type: string
                email:
                  type: string
                is_new:
                  type: boolean
            api_key:
              type: object
              properties:
                key:
                  type: string
                  description: The full API key - SAVE THIS! Only shown once.
                prefix:
                  type: string
                mode:
                  type: string
                permissions:
                  type: array
                  items:
                    type: string
                rate_limit:
                  type: integer
            order:
              type: object
              description: Only present if product_id was specified
              properties:
                order_id:
                  type: string
                checkout_url:
                  type: string
                  format: uri
            next_steps:
              type: object
              additionalProperties:
                type: string

    Error:
      type: object
      properties:
        success:
          type: boolean
          example: false
        error:
          type: object
          properties:
            message:
              type: string
            code:
              type: string

  responses:
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid API key
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
