openapi: 3.0.3
info:
  title: Nyugtázom REST API
  version: 1.1.0
  description: Külső szoftverek nyugta-kiállításához, PDF-letöltéséhez, e-mail-cím javításához/újraküldéséhez és sztornózásához.
servers:
  - url: https://nyugtazom.hu/api/v1
security:
  - bearerAuth: []
paths:
  /receipts:
    post:
      summary: Nyugta kiállítása
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateReceipt'
      responses:
        '201':
          description: A nyugta elkészült
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptSuccess'
              example:
                success: true
                environment: live
                receipt:
                  id: '123'
                  number: NY-2026-000123
                  status: active
                  service: Géllakk készítés
                  price: 8500
                  payment_method: card
                  print_size: A4
                  pdf_url: https://nyugtazom.hu/api/v1/receipts/123/pdf
                  pdf_url_expires_in: 900
                  email:
                    requested: true
                    status: sent
                warning: null
        '401': { $ref: '#/components/responses/Unauthorized' }
        '422': { $ref: '#/components/responses/ValidationError' }
  /receipts/{id}:
    get:
      summary: Nyugta lekérdezése
      parameters: [{ $ref: '#/components/parameters/ReceiptId' }]
      responses:
        '200':
          description: A nyugta adatai
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptSuccess'
        '404': { description: A nyugta nem található }
  /receipts/{id}/pdf:
    get:
      summary: PDF letöltése
      parameters: [{ $ref: '#/components/parameters/ReceiptId' }]
      responses:
        '200':
          description: A nyugta PDF-fájlja bináris application/pdf válaszként
          headers:
            Content-Disposition:
              description: A letöltendő PDF fájlneve
              schema: { type: string, example: 'inline; filename="NY-2026-000123.pdf"' }
          content:
            application/pdf:
              schema: { type: string, format: binary }
  /receipts/{id}/resend-email:
    post:
      summary: Nyugta e-mail-címének javítása és újraküldése
      description: |
        A megadott e-mail-címre javítja a nyugtához tárolt ügyfél e-mail-címet, majd éles módban újraküldi a nyugta PDF-jét.
        Tesztmódban az e-mail-cím frissül az api_test_receipts táblában, de tényleges e-mail-küldés nem történik.
        A művelet csak az API-n keresztül elérhető, a normál webes nyugtakiállítás működését nem módosítja.
      parameters:
        - $ref: '#/components/parameters/ReceiptId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ResendReceiptEmail'
            example:
              customer_email: anna.helyes@example.com
      responses:
        '200':
          description: Az e-mail-cím frissítve; éles módban az újraküldés megtörtént vagy a válasz jelzi a küldési hibát
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ResendEmailSuccess'
              examples:
                liveSent:
                  summary: Éles mód, sikeres újraküldés
                  value:
                    success: true
                    environment: live
                    receipt:
                      id: '123'
                      number: NYGTA-2026-000123
                    email:
                      address: anna.helyes@example.com
                      status: sent
                      database_updated: true
                      message_id: 019c-example-message-id
                    warning: null
                testSuppressed:
                  summary: Tesztmód
                  value:
                    success: true
                    environment: test
                    receipt:
                      id: '12'
                      number: TEST-2026-0003
                    email:
                      address: anna.helyes@example.com
                      status: suppressed_test
                      database_updated: true
                    warning: Tesztmódban az e-mail-címet elmentettük, de tényleges e-mailt nem küldünk.
        '401': { $ref: '#/components/responses/Unauthorized' }
        '404': { description: A nyugta nem található }
        '409': { description: Idempotenciaütközés }
        '422': { $ref: '#/components/responses/ValidationError' }
  /receipts/{id}/void:
    post:
      summary: Nyugta sztornózása
      parameters:
        - $ref: '#/components/parameters/ReceiptId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [reason]
              properties:
                reason: { type: string, maxLength: 500 }
      responses:
        '201':
          description: A sztornóbizonylat elkészült; a receipt.id az új sztornóbizonylat azonosítója
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReceiptSuccess'
              example:
                success: true
                environment: live
                receipt:
                  id: '124'
                  number: NY-2026-000124
                  status: storno
                  service: Géllakk készítés
                  price: -8500
                  payment_method: card
                  print_size: A4
                  pdf_url: https://nyugtazom.hu/api/v1/receipts/124/pdf
                  pdf_url_expires_in: 900
                  email:
                    requested: false
                    status: not_requested
                warning: null
        '409': { description: A nyugta már sztornózott vagy nem sztornózható }
components:
  securitySchemes:
    bearerAuth: { type: http, scheme: bearer, bearerFormat: NyugtazomApiKey }
  parameters:
    ReceiptId:
      name: id
      in: path
      required: true
      schema: { type: integer, format: int64 }
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      description: Egyedi kérésazonosító, amely megakadályozza a dupla nyugtát. Minden új művelethez új értéket, ugyanazon művelet hálózati újrapróbálásához ugyanazt az értéket használd. Javasolt egy UUID v4.
      schema:
        type: string
        minLength: 16
        maxLength: 128
        pattern: '^[A-Za-z0-9._:-]+$'
        example: 550e8400-e29b-41d4-a716-446655440000
  schemas:
    CreateReceipt:
      type: object
      required: [service, price, payment_method, print_size]
      properties:
        service: { type: string, maxLength: 255 }
        price: { type: number, minimum: 0.01, maximum: 899999.99 }
        payment_method: { type: string, enum: [cash, card] }
        print_size: { type: string, enum: [A4, 58mm, 80mm] }
        customer_name: { type: string, maxLength: 200 }
        customer_email: { type: string, format: email, maxLength: 254 }
    ResendReceiptEmail:
      type: object
      required: [customer_email]
      properties:
        customer_email:
          type: string
          format: email
          maxLength: 254
          description: A javított e-mail-cím, amelyet a nyugtához elmentünk és éles módban az újraküldéshez használunk.
    ResendEmailSuccess:
      type: object
      required: [success, environment, receipt, email, warning]
      properties:
        success:
          type: boolean
          enum: [true]
        environment:
          type: string
          enum: [live, test]
        receipt:
          type: object
          required: [id, number]
          properties:
            id: { type: string }
            number: { type: string }
        email:
          type: object
          required: [address, status, database_updated]
          properties:
            address:
              type: string
              format: email
            status:
              type: string
              enum: [sent, failed, suppressed_test]
            database_updated:
              type: boolean
              enum: [true]
            message_id:
              type: string
              nullable: true
              description: A Postmark üzenetazonosítója sikeres éles küldésnél.
            error:
              type: string
              nullable: true
              description: Éles küldési hiba rövid leírása; az adatbázis e-mail-címe ettől még frissült.
        warning:
          type: string
          nullable: true
    ReceiptSuccess:
      type: object
      required: [success, environment, receipt, warning]
      properties:
        success:
          type: boolean
          enum: [true]
        environment:
          type: string
          enum: [live, test]
          description: Az aktuális fiók API-környezete.
        receipt:
          type: object
          required: [id, number, status, service, price, payment_method, print_size, pdf_url, pdf_url_expires_in, email]
          properties:
            id:
              type: string
              description: A nyugta vagy sztornóbizonylat egyedi azonosítója.
            number:
              type: string
              description: A bizonylat sorszáma.
            status:
              type: string
              description: Éles módban active, void vagy storno; tesztmódban test_active, test_void vagy test_storno.
              enum: [active, void, storno, test_active, test_void, test_storno]
            service: { type: string }
            price:
              type: number
              description: A végösszeg; sztornóbizonylatnál negatív érték.
            payment_method: { type: string, enum: [cash, card] }
            print_size: { type: string, enum: [A4, 58mm, 80mm] }
            pdf_url:
              type: string
              format: uri
              description: Böngészőből is megnyitható, 15 percig érvényes, aláírt PDF-letöltési URL. Nem tartalmaz API-kulcsot.
            pdf_url_expires_in:
              type: integer
              example: 900
              description: A PDF-link hátralévő érvényessége másodpercben a válasz létrehozásakor.
            email:
              type: object
              required: [requested, status]
              properties:
                requested:
                  type: boolean
                  description: Érkezett-e ügyfél e-mail-cím a kérésben.
                status:
                  type: string
                  enum: [sent, failed, not_requested, suppressed_test]
                  description: Az e-mail-küldés eredménye. Tesztmódban suppressed_test, mert nem küldünk levelet.
        warning:
          type: string
          nullable: true
          description: Tesztmódban figyelmeztet, hogy a bizonylat nem valódi nyugta; éles módban null.
  responses:
    Unauthorized: { description: Érvénytelen vagy visszavont API-kulcs }
    ValidationError: { description: Hiányzó vagy hibás mezők }
