openapi: 3.1.0
info:
  title: Viva Cloud Terminal SDK — Référence TypeScript
  version: 1.0.0
  description: |
    Documentation de référence du SDK TypeScript `@qrcommunication/viva-cloud-terminal-sdk`.

    Ce document décrit les **classes**, **méthodes**, **paramètres** et **types de retour**
    du SDK — pas les endpoints HTTP sous-jacents.

    Le SDK pilote la **Cloud Terminal API marchand** (`/ecr/v1/`) de Viva Wallet :
    vente, capture de pré-autorisation, remboursements, rebate, sessions et polling.
    Isomorphe : Node 18+, navigateur, Deno, edge runtimes, React Native.

    ## Installation

    ```bash
    npm install @qrcommunication/viva-cloud-terminal-sdk
    ```

    ## Initialisation

    ```ts
    import { VivaCloudTerminalClient } from "@qrcommunication/viva-cloud-terminal-sdk";

    const viva = new VivaCloudTerminalClient({
      clientId: "your-client-id",
      clientSecret: "your-client-secret",
      environment: "demo", // ou "production"
    });
    ```

    ## Ressources disponibles

    | Propriété | Classe | Description |
    |-----------|--------|-------------|
    | `viva.devices` | `DevicesResource` | Recherche des terminaux POS et statut |
    | `viva.transactions` | `TransactionsResource` | Vente, capture preauth, remboursements, rebate, actions |
    | `viva.sessions` | `SessionsResource` | Récupération, listing, abort et polling des sessions |

    ## Montants

    Tous les montants sont en **centimes** (`number`). Exemple : `1170` = 11,70 EUR.
    `currencyCode` est le code ISO 4217 numérique en **string** (`"978"` = EUR).

    ## Authentification

    OAuth2 `client_credentials` → Bearer token. Le token est récupéré sur
    `accounts.vivapayments.com/connect/token` et utilisé contre
    `api.vivapayments.com/ecr/v1/...` (hôtes demo en sandbox). Tous les payloads
    `/ecr/v1/` sont en **camelCase**.

    ## Body vide sur succès

    La plupart des endpoints `/ecr/v1/transactions:*` répondent HTTP 200 sans body.
    Les méthodes `transactions` retournent un `TransactionResult` : pollez la session
    via `sessions.get()` / `pollUntilComplete()` pour le résultat réel.

    ## Gestion d'erreurs

    | Erreur | Quand |
    |--------|-------|
    | `AuthenticationError` | Échec OAuth2 (identifiants invalides, 401) |
    | `ApiError` | Erreur HTTP retournée par l'API Viva (4xx, 5xx) |
    | `VivaError` | Classe de base pour toutes les erreurs SDK |
  contact:
    name: QrCommunication
    email: contact@qrcommunication.com
    url: https://qrcommunication.com
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT

tags:
  - name: VivaCloudTerminalClient
    description: |
      Point d'entrée du SDK — instanciation, gestion du token, polling raccourci.

      ```ts
      import { VivaCloudTerminalClient } from "@qrcommunication/viva-cloud-terminal-sdk";
      ```
  - name: Devices
    description: |
      `viva.devices` — Découverte des terminaux POS (EFT POS) et de leur statut.

      ```ts
      const devices = await viva.devices.search({ statusId: 1 });
      ```
  - name: Transactions
    description: |
      `viva.transactions` — Vente, capture de pré-autorisation, remboursements,
      rebate et actions sur le terminal.

      ```ts
      const sale = await viva.transactions.sale({ terminalId: "16000010", amount: 1170, cashRegisterId: "CR-01" });
      ```
  - name: Sessions
    description: |
      `viva.sessions` — Récupération, listing, abort et polling des sessions.

      ```ts
      const result = await viva.pollUntilComplete(sale.sessionId);
      ```
  - name: Enums
    description: |
      Enums et helpers fournis par le SDK.

      - `Environment` — `"demo"` | `"production"`
      - `EcrEventId` — constantes d'événement de session + helpers
        (`ecrEventIdFrom`, `isSuccessfulEvent`, `isInProgress`, `isTerminalEvent`, `ecrEventLabel`)
  - name: Errors
    description: |
      Hiérarchie d'erreurs du SDK.

      ```
      Error
      └── VivaError
          ├── ApiError
          └── AuthenticationError
      ```

paths:
  # ============================================================
  # VivaCloudTerminalClient
  # ============================================================
  /VivaCloudTerminalClient/__construct:
    post:
      tags: [VivaCloudTerminalClient]
      operationId: VivaCloudTerminalClient__construct
      summary: new VivaCloudTerminalClient(options)
      description: |
        Instancie le client SDK. L'authentification OAuth2 est automatique au premier appel API.

        ```ts
        const viva = new VivaCloudTerminalClient({
          clientId: "your-client-id",
          clientSecret: "your-client-secret",
          environment: "demo",
        });
        ```
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClientConstructorParams'
      responses:
        '200':
          description: Instance `VivaCloudTerminalClient` créée
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientInstance'

  /VivaCloudTerminalClient/invalidateToken:
    post:
      tags: [VivaCloudTerminalClient]
      operationId: VivaCloudTerminalClient_invalidateToken
      summary: "viva.invalidateToken()"
      description: |
        Supprime le token OAuth caché, forçant un nouveau handshake au prochain appel.

        ```ts
        viva.invalidateToken();
        ```
      responses:
        '200':
          description: "`void` — Le token est invalidé"

  /VivaCloudTerminalClient/pollUntilComplete:
    get:
      tags: [VivaCloudTerminalClient]
      operationId: VivaCloudTerminalClient_pollUntilComplete
      summary: "viva.pollUntilComplete()"
      description: |
        Raccourci vers `SessionsResource.pollUntilComplete()`. Poll une session
        jusqu'à un état terminal ou expiration du timeout.

        ```ts
        const result = await viva.pollUntilComplete(sale.sessionId, { timeoutSeconds: 90 });
        ```
      parameters:
        - name: sessionId
          in: query
          required: true
          schema:
            type: string
            format: uuid
          description: UUID de la session à poller
        - name: options
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/PollOptions'
          description: "Options de polling (timeoutSeconds, intervalMs)"
      responses:
        '200':
          description: État final de la session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Session'

  /VivaCloudTerminalClient/getConfig:
    get:
      tags: [VivaCloudTerminalClient]
      operationId: VivaCloudTerminalClient_getConfig
      summary: "viva.getConfig()"
      description: |
        Retourne l'objet `CloudTerminalConfig` (hôtes, environnement, timeout).

        ```ts
        const config = viva.getConfig();
        config.apiUrl();      // "https://demo-api.vivapayments.com"
        config.accountsUrl(); // "https://demo-accounts.vivapayments.com"
        ```
      responses:
        '200':
          description: Objet `CloudTerminalConfig`
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Config'

  # ============================================================
  # Devices
  # ============================================================
  /Devices/search:
    post:
      tags: [Devices]
      operationId: Devices_search
      summary: "viva.devices.search()"
      description: |
        Recherche les terminaux POS, filtrage optionnel par statut et/ou source code.

        Endpoint : `POST /ecr/v1/devices:search`. Recommandé en pré-flight avant
        toute transaction (confirmer que le terminal est `Live`, `statusId` 1).

        Valeurs `statusId` : 0 = WareHouse, 1 = Live, 2 = Ready To Ship,
        3 = In Stock, 4 = Pending Key Injection, 5 = Lost, 6 = Broken.

        ```ts
        const devices = await viva.devices.search({ statusId: 1 });
        ```
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                statusId:
                  type: integer
                  description: Filtrer par statut du terminal
                sourceCode:
                  type: string
                  description: Code d'identification personnalisé assigné au terminal
      responses:
        '200':
          description: Liste des terminaux (JsonObject)
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Device'
        '401':
          description: "`AuthenticationError` — OAuth2 invalide"

  # ============================================================
  # Transactions
  # ============================================================
  /Transactions/sale:
    post:
      tags: [Transactions]
      operationId: Transactions_sale
      summary: "viva.transactions.sale()"
      description: |
        Initie une vente sur un terminal POS.

        Endpoint : `POST /ecr/v1/transactions:sale`. Retourne un `TransactionResult` ;
        le résultat réel s'obtient en pollant la session.

        ```ts
        const sale = await viva.transactions.sale({
          terminalId: "16000010",
          amount: 2599,
          cashRegisterId: "CR-01",
          customerTrns: "Table 12",
          showReceipt: true,
        });

        const final = await viva.pollUntilComplete(sale.sessionId, { timeoutSeconds: 90 });
        ```
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SaleParams'
      responses:
        '200':
          description: Vente dispatchée vers le terminal
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionResult'
        '409':
          description: "`ApiError` — Session avec cet ID existe déjà"

  /Transactions/capturePreauth:
    post:
      tags: [Transactions]
      operationId: Transactions_capturePreauth
      summary: "viva.transactions.capturePreauth()"
      description: |
        Capture une transaction pré-autorisée.

        Endpoint : `POST /ecr/v1/transactions:preauth-completion`. Capture le montant
        retenu par la pré-autorisation identifiée par `parentSessionId`.

        ```ts
        const capture = await viva.transactions.capturePreauth({
          parentSessionId: preauth.sessionId,
          terminalId: "16000010",
          amount: 4200,
          cashRegisterId: "CR-01",
        });
        ```
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CapturePreauthParams'
      responses:
        '200':
          description: Capture dispatchée
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionResult'

  /Transactions/refund:
    post:
      tags: [Transactions]
      operationId: Transactions_refund
      summary: "viva.transactions.refund()"
      description: |
        Rembourse une vente, en référençant la session originale.

        Endpoint : `POST /ecr/v1/transactions:refund`. Un nouveau `sessionId` est
        généré pour le remboursement ; `parentSessionId` référence la vente originale.

        ```ts
        const refund = await viva.transactions.refund({
          parentSessionId: sale.sessionId,
          terminalId: "16000010",
          amount: 1170,
          cashRegisterId: "CR-01",
        });
        ```
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RefundParams'
      responses:
        '200':
          description: Remboursement dispatché
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionResult'

  /Transactions/unreferencedRefund:
    post:
      tags: [Transactions]
      operationId: Transactions_unreferencedRefund
      summary: "viva.transactions.unreferencedRefund()"
      description: |
        Remboursement autonome (non référencé), non lié à une vente originale.

        Endpoint : `POST /ecr/v1/transactions:unreferenced-refund`.

        ```ts
        const refund = await viva.transactions.unreferencedRefund({
          terminalId: "16000010",
          amount: 1500,
          cashRegisterId: "CR-01",
        });
        ```
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StandaloneRefundParams'
      responses:
        '200':
          description: Remboursement autonome dispatché
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionResult'

  /Transactions/fastRefund:
    post:
      tags: [Transactions]
      operationId: Transactions_fastRefund
      summary: "viva.transactions.fastRefund()"
      description: |
        Remboursement rapide (swift) sur Visa / Mastercard / Maestro.

        Endpoint : `POST /ecr/v1/transactions:fast-refund`.

        ```ts
        const refund = await viva.transactions.fastRefund({
          terminalId: "16000010",
          amount: 1170,
          cashRegisterId: "CR-01",
        });
        ```
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StandaloneRefundParams'
      responses:
        '200':
          description: Remboursement rapide dispatché
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionResult'

  /Transactions/rebate:
    post:
      tags: [Transactions]
      operationId: Transactions_rebate
      summary: "viva.transactions.rebate()"
      description: |
        Rabais vers une carte Visa / Mastercard / Maestro.

        Endpoint : `POST /ecr/v1/transactions:rebate`.

        ```ts
        const rebate = await viva.transactions.rebate({
          terminalId: "16000010",
          amount: 500,
          cashRegisterId: "CR-01",
        });
        ```
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StandaloneRefundParams'
      responses:
        '200':
          description: Rabais dispatché
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TransactionResult'

  /Transactions/createAction:
    post:
      tags: [Transactions]
      operationId: Transactions_createAction
      summary: "viva.transactions.createAction()"
      description: |
        Crée une action à invoquer sur un terminal POS (ex : `aade-fim-control`).

        Endpoint : `POST /ecr/v1/actions`. Le payload est transmis tel quel
        (camelCase) et doit inclure `terminalId`, `cashRegisterId`, `actionType`
        et `request`.

        ```ts
        const action = await viva.transactions.createAction({
          terminalId: "16000010",
          cashRegisterId: "XDE384678UY",
          actionType: "aade-fim-control",
          request: { token: "ECR0210U/RCFB77000041/CMAC_K:...:CC5FFF" },
        });
        console.log(action.actionId);
        ```
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [terminalId, cashRegisterId, actionType, request]
              properties:
                terminalId:
                  type: string
                cashRegisterId:
                  type: string
                actionType:
                  type: string
                  enum: [aade-fim-control]
                request:
                  type: object
        description: "Corps de la requête d'action (passé tel quel, camelCase)"
      responses:
        '200':
          description: Action créée
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ActionResult'

  /Transactions/getAction:
    get:
      tags: [Transactions]
      operationId: Transactions_getAction
      summary: "viva.transactions.getAction()"
      description: |
        Récupère le résultat d'une action précédemment créée.

        Endpoint : `GET /ecr/v1/actions/{actionId}`. Retourne HTTP 202 (body vide → `{}`)
        tant que l'action est en cours, ou le résultat une fois terminée.

        ```ts
        const result = await viva.transactions.getAction("f7287549-e93a-4d33-b936-000027d326d0");

        if (result.successfullyProcessed === true) {
          console.log(result.response);
        }
        ```
      parameters:
        - name: actionId
          in: query
          required: true
          schema:
            type: string
          description: ID de l'action (retourné par `createAction()`)
      responses:
        '200':
          description: Résultat de l'action (JsonObject)
          content:
            application/json:
              schema:
                type: object
        '202':
          description: "Traitement de l'action non terminé (body vide → {})"
        '404':
          description: "`ApiError` — Action introuvable"

  # ============================================================
  # Sessions
  # ============================================================
  /Sessions/get:
    get:
      tags: [Sessions]
      operationId: Sessions_get
      summary: "viva.sessions.get()"
      description: |
        Récupère une session par son id.

        Endpoint : `GET /ecr/v1/sessions/{sessionId}`.

        ```ts
        const session = await viva.sessions.get(sale.sessionId);
        console.log(session.eventId);       // 0 = succès
        console.log(session.transactionId); // UUID de la transaction Viva
        ```
      parameters:
        - name: sessionId
          in: query
          required: true
          schema:
            type: string
            format: uuid
          description: UUID de la session
      responses:
        '200':
          description: Données de la session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Session'

  /Sessions/listByDate:
    get:
      tags: [Sessions]
      operationId: Sessions_listByDate
      summary: "viva.sessions.listByDate()"
      description: |
        Liste toutes les sessions effectuées une date donnée.

        Endpoint : `GET /ecr/v1/sessions?date=YYYY-MM-DD`.

        ```ts
        const sessions = await viva.sessions.listByDate({ date: "2026-06-06" });
        ```
      parameters:
        - name: date
          in: query
          required: true
          schema:
            type: string
            format: date
          description: "Date au format `YYYY-MM-DD`"
        - name: aadeAutonomouslyOnly
          in: query
          required: false
          schema:
            type: boolean
          description: Filtrer aux sessions AADE-autonomes uniquement (Grèce)
      responses:
        '200':
          description: Liste de sessions (JsonObject)
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object

  /Sessions/abort:
    delete:
      tags: [Sessions]
      operationId: Sessions_abort
      summary: "viva.sessions.abort()"
      description: |
        Annule une session active.

        Endpoint : `DELETE /ecr/v1/sessions/{sessionId}?cashRegisterId=...`.
        Seule la caisse ayant créé la transaction peut l'annuler.

        ```ts
        await viva.sessions.abort(sale.sessionId, "CR-01");
        ```
      parameters:
        - name: sessionId
          in: query
          required: true
          schema:
            type: string
            format: uuid
          description: UUID de la session à annuler
        - name: cashRegisterId
          in: query
          required: true
          schema:
            type: string
          description: Identification de la caisse
      responses:
        '200':
          description: Session annulée
          content:
            application/json:
              schema:
                type: object

  /Sessions/pollUntilComplete:
    get:
      tags: [Sessions]
      operationId: Sessions_pollUntilComplete
      summary: "viva.sessions.pollUntilComplete()"
      description: |
        Poll une session jusqu'à un état terminal ou expiration du timeout.

        Continue de poller tant que `eventId` vaut `IN_PROGRESS` (1100), en dormant
        `intervalMs` entre les tentatives. S'arrête aussi sur un `eventId` inconnu
        (fail-safe). En cas de timeout sans réponse, retourne
        `{ success: false, eventId: 1003, message: "SDK poll timeout" }`.

        ```ts
        const result = await viva.sessions.pollUntilComplete(sale.sessionId, { timeoutSeconds: 90, intervalMs: 2000 });
        ```
      parameters:
        - name: sessionId
          in: query
          required: true
          schema:
            type: string
            format: uuid
          description: UUID de la session à poller
        - name: options
          in: query
          required: false
          schema:
            $ref: '#/components/schemas/PollOptions'
          description: "Options de polling (timeoutSeconds, intervalMs)"
      responses:
        '200':
          description: État final de la session
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Session'

components:
  schemas:
    ClientConstructorParams:
      type: object
      required: [clientId, clientSecret]
      properties:
        clientId:
          type: string
          description: Client ID OAuth2 (grant client_credentials)
        clientSecret:
          type: string
          description: Secret OAuth2
        environment:
          type: string
          enum: [demo, production]
          default: demo
        timeoutMs:
          type: integer
          default: 30000
          description: Timeout des requêtes en millisecondes
        fetch:
          type: object
          description: "Implémentation fetch custom (polyfill / mock)"

    ClientInstance:
      type: object
      description: Instance VivaCloudTerminalClient
      properties:
        devices:
          type: object
          description: "DevicesResource — POST /ecr/v1/devices:search"
        transactions:
          type: object
          description: "TransactionsResource — /ecr/v1/transactions:* + /ecr/v1/actions"
        sessions:
          type: object
          description: "SessionsResource — GET/DELETE /ecr/v1/sessions..."

    Config:
      type: object
      description: CloudTerminalConfig
      properties:
        clientId:
          type: string
        environment:
          type: string
          enum: [demo, production]
        timeoutMs:
          type: integer
        accountsUrl:
          type: string
          example: https://demo-accounts.vivapayments.com
        apiUrl:
          type: string
          example: https://demo-api.vivapayments.com

    Device:
      type: object
      properties:
        terminalId:
          type: string
          example: "16000010"
        statusId:
          type: integer
          example: 1
        sourceCode:
          type: string
          example: "543679"
        virtualTerminalId:
          type: string
          example: cUOIpgY5RqKF5SC0BV6ZCl

    SaleParams:
      type: object
      required: [terminalId, amount, cashRegisterId]
      properties:
        terminalId:
          oneOf:
            - type: string
            - type: integer
          description: ID du terminal cible
        amount:
          type: integer
          description: Montant à autoriser, en centimes
        cashRegisterId:
          type: string
          description: Identification de la caisse
        merchantReference:
          type: string
          description: "Référence marchand (défaut: SDK-{sessionId})"
        currencyCode:
          type: string
          default: "978"
          description: "Code ISO 4217 numérique en string ('978' = EUR)"
        tipAmount:
          type: integer
          default: 0
          description: Pourboire en centimes (incompatible avec preauth)
        preauth:
          type: boolean
          description: Flag de pré-autorisation
        customerTrns:
          type: string
          description: Référence client
        paymentMethod:
          type: string
          description: "Méthode de paiement affichée (ex: CardPresent)"
        skipSurcharge:
          type: boolean
        showTransactionResult:
          type: boolean
        showReceipt:
          type: boolean
        sessionId:
          type: string
          format: uuid
          description: UUID de session (auto-généré si omis)
        extra:
          type: object
          description: "Champs API additionnels (ex: fiscalisationData)"

    CapturePreauthParams:
      type: object
      required: [parentSessionId, terminalId, amount, cashRegisterId]
      properties:
        parentSessionId:
          type: string
          format: uuid
          description: UUID de session de la pré-autorisation à capturer
        terminalId:
          oneOf:
            - type: string
            - type: integer
        amount:
          type: integer
          description: Montant à capturer, en centimes
        cashRegisterId:
          type: string
        merchantReference:
          type: string
        currencyCode:
          type: string
          default: "978"
        customerTrns:
          type: string
        showTransactionResult:
          type: boolean
        showReceipt:
          type: boolean
        sessionId:
          type: string
          format: uuid
        extra:
          type: object

    RefundParams:
      type: object
      required: [parentSessionId, terminalId, amount, cashRegisterId]
      properties:
        parentSessionId:
          type: string
          format: uuid
          description: UUID de session de la vente originale à rembourser
        terminalId:
          oneOf:
            - type: string
            - type: integer
        amount:
          type: integer
          description: Montant à rembourser, en centimes
        cashRegisterId:
          type: string
        merchantReference:
          type: string
        currencyCode:
          type: string
          default: "978"
        customerTrns:
          type: string
        showTransactionResult:
          type: boolean
        showReceipt:
          type: boolean
        sessionId:
          type: string
          format: uuid
        extra:
          type: object

    StandaloneRefundParams:
      type: object
      required: [terminalId, amount, cashRegisterId]
      description: "Paramètres pour unreferencedRefund(), fastRefund() et rebate()"
      properties:
        terminalId:
          oneOf:
            - type: string
            - type: integer
        amount:
          type: integer
          description: Montant, en centimes
        cashRegisterId:
          type: string
        merchantReference:
          type: string
        currencyCode:
          type: string
          default: "978"
        customerTrns:
          type: string
        showTransactionResult:
          type: boolean
        showReceipt:
          type: boolean
        sessionId:
          type: string
          format: uuid
        extra:
          type: object

    PollOptions:
      type: object
      properties:
        timeoutSeconds:
          type: integer
          default: 120
          description: Temps d'attente total maximum (secondes)
        intervalMs:
          type: integer
          default: 3000
          description: Délai entre deux tentatives (millisecondes)

    TransactionResult:
      type: object
      description: "Résultat — pollez la session pour le résultat réel"
      properties:
        sessionId:
          type: string
          format: uuid
          description: UUID de session utilisé (à poller)
        response:
          type: object
          description: "Body API brut (souvent vide en succès)"

    ActionResult:
      type: object
      properties:
        terminalId:
          type: string
        cashRegisterId:
          type: string
        actionType:
          type: string
          enum: [aade-fim-control]
        actionId:
          type: string
          format: uuid
          example: f7287549-e93a-4d33-b936-000027d326d0

    Session:
      type: object
      description: "État d'une session (champs dynamiques selon l'API)"
      properties:
        eventId:
          type: integer
          description: "ID d'événement (voir EcrEventId)"
        success:
          type: boolean
        transactionId:
          type: string
          format: uuid
        amount:
          type: integer
          description: Montant en centimes

    ApiError:
      type: object
      description: "ApiError — httpStatus, getErrorText(), getErrorCode()"
      properties:
        httpStatus:
          type: integer
        errorText:
          type: string
          nullable: true
        errorCode:
          type: integer
          nullable: true
