openapi: 3.0.0
paths:
  /invoices/scheduled:
    post:
      description: >-
        Creates an invoice template (type INVOICE) that is issued automatically
        — and reported to the AT — on every occurrence of the given frequency.
        The issued documents appear in GET /invoices with scheduleTemplateId
        equal to the id returned here. Requires a plan with recurring invoices.
      operationId: ScheduledInvoicesController_create
      parameters:
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: The document to repeat and its schedule
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateScheduledInvoiceDto'
      responses:
        '201':
          description: Recurring invoice created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScheduledInvoiceResponseDto'
        '400':
          description: >-
            Invalid data, or a schedule with no occurrences (endDate before
            startDate, say)
        '401':
          description: Unauthorized - API key missing or invalid
        '403':
          description: The account plan does not include recurring invoices
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
      summary: Create recurring invoice
      tags:
        - Recurring invoices
    get:
      description: >-
        Returns the account's recurring-invoice templates, in any schedule
        status (see schedule.status). For the documents a schedule has already
        issued use GET /invoices?scheduleTemplateId={id}.
      operationId: ScheduledInvoicesController_findAll
      parameters:
        - name: offset
          required: false
          in: query
          description: Number of records to skip (offset)
          schema:
            default: 0
            example: 0
            type: number
        - name: limit
          required: false
          in: query
          description: Maximum number of records to return
          schema:
            default: 20
            example: 20
            type: number
        - name: sort
          required: false
          in: query
          description: Sort field and order (e.g. createdAt:desc)
          schema:
            example: createdAt:desc
            type: string
        - name: customerId
          required: false
          in: query
          description: Filter by one customer's schedules
          schema:
            example: 6863b1513117c5892ff55296
            type: string
      responses:
        '200':
          description: List of recurring invoices returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ScheduledInvoiceResponseDto'
        '400':
          description: Invalid parameters
        '401':
          description: Unauthorized - API key missing or invalid
      security:
        - x-api-key: []
      summary: List recurring invoices
      tags:
        - Recurring invoices
  /invoices/scheduled/{id}:
    get:
      description: Returns one recurring-invoice template and its schedule
      operationId: ScheduledInvoicesController_findOne
      parameters:
        - name: id
          required: true
          in: path
          description: Recurring invoice ID
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
      responses:
        '200':
          description: Recurring invoice found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScheduledInvoiceResponseDto'
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Recurring invoice not found
      security:
        - x-api-key: []
      summary: Get recurring invoice by ID
      tags:
        - Recurring invoices
    patch:
      description: >-
        Changes the schedule (frequency, dates, time, auto-send) or
        pauses/resumes issuing. Only the fields sent are changed; null is
        accepted on endDate only. To change the document itself (items,
        customer, notes) use PATCH /invoices/{id} with the same id.
      operationId: ScheduledInvoicesController_update
      parameters:
        - name: id
          required: true
          in: path
          description: Recurring invoice ID
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: Schedule fields to update
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateScheduledInvoiceDto'
      responses:
        '200':
          description: Recurring invoice updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScheduledInvoiceResponseDto'
        '400':
          description: >-
            Invalid data, or a schedule with no occurrences (endDate before
            startDate, say)
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Recurring invoice not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
      summary: Update recurring invoice
      tags:
        - Recurring invoices
    delete:
      description: >-
        Deletes the template and ends issuing. Documents already issued are kept
        but stop referencing this schedule (scheduleTemplateId) — save the ids
        from GET /invoices?scheduleTemplateId={id} before deleting if you need
        to reconcile them later. To stop without losing the history, pause with
        PATCH /invoices/scheduled/{id} and status=PAUSED.
      operationId: ScheduledInvoicesController_delete
      parameters:
        - name: id
          required: true
          in: path
          description: Recurring invoice ID
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      responses:
        '200':
          description: Recurring invoice deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteInvoiceResponseDto'
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Recurring invoice not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
      summary: Delete recurring invoice
      tags:
        - Recurring invoices
  /invoices:
    post:
      description: Creates a draft invoice without issuing it
      operationId: InvoicesController_create
      parameters:
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: Data required to create the draft invoice
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateInvoiceDto'
      responses:
        '201':
          description: Draft invoice created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateInvoiceResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Create draft invoice
      tags:
        - Invoices
    get:
      description: >-
        Returns a paginated, filterable list of invoices. By default returns 20
        invoices starting at offset 0.
      operationId: InvoicesController_findAll
      parameters:
        - name: offset
          required: false
          in: query
          description: Number of records to skip (offset)
          schema:
            default: 0
            example: 0
            type: number
        - name: limit
          required: false
          in: query
          description: Maximum number of records to return
          schema:
            default: 20
            example: 20
            type: number
        - name: sort
          required: false
          in: query
          description: Sort field and order (e.g. date:desc, number:asc)
          schema:
            example: date:desc
            type: string
        - name: search
          required: false
          in: query
          description: Global search term (number, customer, etc.)
          schema:
            example: FT
            type: string
        - name: documentType
          required: false
          in: query
          description: Filter by document type
          schema:
            example: INVOICE
            type: string
            enum:
              - CREDIT_NOTE
              - DEBIT_NOTE
              - INVOICE
              - INVOICE_RECEIPT
              - RECEIPT
              - SIMPLIFIED_INVOICE
        - name: status
          required: false
          in: query
          description: Filter by status
          schema:
            example: ISSUED
            type: string
            enum:
              - CANCELED
              - CREATED
              - DRAFT
              - ISSUED
              - PAID
              - PROCESSING
              - SCHEDULED
        - name: aggregatedStatus
          required: false
          in: query
          description: Filter by aggregated status
          schema:
            example: UNPAID
            type: string
            enum:
              - DRAFT
              - OVERDUE
              - PAID
              - PENDING
              - SCHEDULED
              - UNPAID
        - name: date
          required: false
          in: query
          description: Filter by a specific date (ISO 8601 with timezone)
          schema:
            example: '2025-01-15T00:00:00.000Z'
            type: string
        - name: dueDate
          required: false
          in: query
          description: Filter by a specific due date (ISO 8601 with timezone)
          schema:
            example: '2025-02-15T00:00:00.000Z'
            type: string
        - name: fromDate
          required: false
          in: query
          description: Filter from this date (ISO 8601 with timezone)
          schema:
            example: '2025-01-01T00:00:00.000Z'
            type: string
        - name: toDate
          required: false
          in: query
          description: Filter up to this date (ISO 8601 with timezone)
          schema:
            example: '2025-12-31T23:59:59.999Z'
            type: string
        - name: currency
          required: false
          in: query
          description: Filter by currency
          schema:
            example: EUR
            type: string
        - name: description
          required: false
          in: query
          description: Filter by description
          schema:
            example: Serviços de consultoria
            type: string
        - name: notes
          required: false
          in: query
          description: Filter by notes
          schema:
            example: Pagamento antecipado
            type: string
        - name: parentInvoiceId
          required: false
          in: query
          description: >-
            Filter by the documents spawned from the given invoice (receipts,
            credit notes and debit notes). Combine with documentType to select a
            single kind, e.g. the receipts issued for an invoice.
          schema:
            example: 68483e978073231c3947077c
            type: string
        - name: scheduleTemplateId
          required: false
          in: query
          description: >-
            Filter by the documents issued by a recurring invoice (the id
            returned by POST /invoices/scheduled). This is how to reconcile a
            schedule with the documents that went out.
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: filterAllStatusesByDate
          required: false
          in: query
          description: Apply the date filter to all statuses
          schema:
            example: false
            type: boolean
        - name: includeATInvoices
          required: false
          in: query
          description: Include invoices imported from the AT
          schema:
            default: false
            example: false
            type: boolean
      responses:
        '200':
          description: List of invoices returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - taxPointDate
                  properties:
                    id:
                      type: string
                      example: 68483e978073231c3947077c
                    number:
                      type: string
                      example: FT 2025/001
                    documentType:
                      type: string
                      example: INVOICE
                    status:
                      type: string
                      example: ISSUED
                    date:
                      type: string
                      format: date-time
                      example: '2025-10-30T10:41:53.097Z'
                    taxPointDate:
                      type: string
                      format: date-time
                      nullable: true
                      description: >-
                        Date of supply, when recorded (art. 36.º n.º 5 al. f)
                        CIVA). Comes back null when it was not recorded — the
                        issue date applies in that case.
                      example: '2025-10-20T07:00:00.000Z'
                    dueDate:
                      type: string
                      format: date-time
                      example: '2025-11-30T10:41:53.097Z'
                    currency:
                      type: string
                      example: EUR
                    parentInvoiceId:
                      type: string
                      nullable: true
                      description: >-
                        The invoice that spawned this document. Populated on
                        receipts, credit notes and debit notes; null on an
                        invoice.
                      example: 68483e978073231c3947077c
                    parentInvoiceNumber:
                      type: string
                      nullable: true
                      description: Number of the originating invoice
                      example: FT 2025/001
                    parentInvoiceDate:
                      type: string
                      format: date-time
                      nullable: true
                      description: Date of the originating invoice
                      example: '2025-10-30T10:41:53.097Z'
                    parentInvoiceType:
                      type: string
                      nullable: true
                      description: Document type of the originating invoice
                      example: INVOICE
                    scheduleTemplateId:
                      type: string
                      nullable: true
                      description: >-
                        Recurring invoice that issued this document. Null on a
                        manually created document.
                      example: 6900afc7e9a04d2adc897c68
                    summary:
                      type: object
                      properties:
                        amountWithoutTax:
                          type: number
                        amountWithTax:
                          type: number
                        taxAmount:
                          type: number
                        total:
                          type: number
                    customer:
                      type: object
                      properties:
                        ref:
                          type: string
                        data:
                          type: object
                          properties:
                            name:
                              type: string
                            taxpayerNumber:
                              type: string
                            email:
                              type: string
        '400':
          description: Invalid parameters
        '401':
          description: Unauthorized - API key missing or invalid
      security:
        - x-api-key: []
        - bearer: []
      summary: List invoices
      tags:
        - Invoices
  /invoices/credit-notes:
    post:
      description: >-
        Creates a credit note that fully reverses the invoice referenced by
        parentInvoiceId. The items and the customer are copied from the original
        invoice. By default the credit note is issued (issue=true).
      operationId: InvoicesController_createCreditNote
      parameters:
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: Data required to create the credit note
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCreditNoteDto'
      responses:
        '201':
          description: Credit note created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateCreditNoteResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Invoice to reverse (parentInvoiceId) not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Create credit note (full reversal)
      tags:
        - Invoices
  /invoices/{id}:
    patch:
      description: >-
        Updates the fields of a draft invoice. Only the provided fields are
        changed.
      operationId: InvoicesController_update
      parameters:
        - name: id
          required: true
          in: path
          description: Unique invoice identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: Fields to update on the draft invoice
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateInvoiceDto'
      responses:
        '200':
          description: Draft invoice updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateInvoiceResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Invoice not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Update draft invoice
      tags:
        - Invoices
    get:
      description: Returns a single invoice by its unique identifier
      operationId: InvoicesController_findOne
      parameters:
        - name: id
          required: true
          in: path
          description: Unique invoice identifier
          schema:
            example: 68483e978073231c3947077c
            type: string
      responses:
        '200':
          description: Invoice found
          content:
            application/json:
              schema:
                type: object
                required:
                  - taxPointDate
                properties:
                  id:
                    type: string
                    example: 68483e978073231c3947077c
                  number:
                    type: string
                    example: FT 2025/001
                  atcud:
                    type: string
                  shortHash:
                    type: string
                  documentType:
                    type: string
                    example: INVOICE
                  status:
                    type: string
                    example: ISSUED
                  updatedAt:
                    type: string
                    format: date-time
                    description: Draft revision to pass as expectedUpdatedAt when issuing.
                  date:
                    type: string
                    format: date-time
                    example: '2025-10-30T10:41:53.097Z'
                  taxPointDate:
                    type: string
                    format: date-time
                    nullable: true
                    description: >-
                      Date of supply, when recorded (art. 36.º n.º 5 al. f)
                      CIVA). Comes back null when it was not recorded — the
                      issue date applies in that case.
                    example: '2025-10-20T07:00:00.000Z'
                  dueDate:
                    type: string
                    format: date-time
                    example: '2025-11-30T10:41:53.097Z'
                  currency:
                    type: string
                    example: EUR
                  description:
                    type: string
                  notes:
                    type: string
                  cae:
                    type: string
                  createdAt:
                    type: string
                    format: date-time
                    example: '2025-10-30T10:41:53.097Z'
                  issuedAt:
                    type: string
                    format: date-time
                    example: '2025-10-30T10:41:53.097Z'
                  parentInvoiceId:
                    type: string
                    nullable: true
                    description: >-
                      The invoice that spawned this document. Populated on
                      receipts, credit notes and debit notes; null on an
                      invoice.
                    example: 68483e978073231c3947077c
                  parentInvoiceNumber:
                    type: string
                    nullable: true
                    description: Number of the originating invoice
                    example: FT 2025/001
                  parentInvoiceDate:
                    type: string
                    format: date-time
                    nullable: true
                    description: Date of the originating invoice
                    example: '2025-10-30T10:41:53.097Z'
                  parentInvoiceType:
                    type: string
                    nullable: true
                    description: Document type of the originating invoice
                    example: INVOICE
                  syncWithAt:
                    type: object
                    properties:
                      status:
                        type: string
                      atCode:
                        type: string
                      atMessage:
                        type: string
                  series:
                    type: object
                    properties:
                      ref:
                        type: string
                      name:
                        type: string
                  customer:
                    type: object
                    properties:
                      ref:
                        type: string
                      data:
                        type: object
                        properties:
                          name:
                            type: string
                          taxpayerNumber:
                            type: string
                          email:
                            type: string
                          address:
                            type: string
                          postalCode:
                            type: string
                          city:
                            type: string
                          country:
                            type: string
                          phone:
                            type: string
                          mobile:
                            type: string
                  summary:
                    type: object
                    properties:
                      amountWithoutTax:
                        type: number
                      amountWithTax:
                        type: number
                      amountWithoutTaxWithoutDiscount:
                        type: number
                      taxAmount:
                        type: number
                      globalDiscountType:
                        type: string
                        enum:
                          - PERCENT
                          - AMOUNT
                      globalDiscountPercent:
                        type: number
                      globalDiscountAmount:
                        type: number
                      total:
                        type: number
                      totalToPay:
                        type: number
                      withholdingTaxAmount:
                        type: number
                      creditNotesTotal:
                        type: number
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        ref:
                          type: string
                        meta:
                          type: object
                          properties:
                            quantity:
                              type: number
                            amountWithoutTax:
                              type: number
                            amountWithTax:
                              type: number
                            taxAmount:
                              type: number
                            discountAmount:
                              type: number
                            unitItemDiscountPercent:
                              type: number
                            unitItemDiscountAmount:
                              type: number
                            unitDiscountPercent:
                              type: number
                            unitDiscountAmount:
                              type: number
                            unitAmountWithoutTax:
                              type: number
                            unitAmountWithTax:
                              type: number
                            withholdingTaxAmount:
                              type: number
                            withholdingTaxEnabled:
                              type: boolean
                        data:
                          type: object
                          properties:
                            name:
                              type: string
                            description:
                              type: string
                            type:
                              type: string
                            unitPrice:
                              type: number
                            vatRate:
                              type: string
                            unitDiscountType:
                              type: string
                              enum:
                                - PERCENT
                                - AMOUNT
                            unitDiscountPercent:
                              type: number
                            unitDiscountAmount:
                              type: number
                  payment:
                    type: object
                    properties:
                      method:
                        type: string
                      date:
                        type: string
                        format: date-time
                        example: '2025-10-30T10:41:53.097Z'
                  qrCode:
                    type: object
                    properties:
                      url:
                        type: string
                      data:
                        type: string
                      imageData:
                        type: string
                  issuer:
                    type: object
                    properties:
                      ref:
                        type: string
                      data:
                        type: object
                        properties:
                          name:
                            type: string
                          taxPayerNumber:
                            type: string
                          address:
                            type: string
                          city:
                            type: string
                          postalCode:
                            type: string
                          country:
                            type: string
        '400':
          description: Invalid ID
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Invoice not found
      security:
        - x-api-key: []
        - bearer: []
      summary: Get invoice by ID
      tags:
        - Invoices
    delete:
      description: Deletes the invoice with the given ID.
      operationId: InvoicesController_delete
      parameters:
        - name: id
          required: true
          in: path
          description: Unique invoice identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      responses:
        '200':
          description: Invoice deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteInvoiceResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Invoice not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Delete invoice
      tags:
        - Invoices
  /invoices/{id}/issue:
    post:
      description: Issues the invoice with the given ID.
      operationId: InvoicesController_issue
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IssueInvoiceDto'
      responses:
        '200':
          description: Invoice issued successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IssueInvoiceResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Issue invoice
      tags:
        - Invoices
  /invoices/{id}/pay:
    post:
      description: >-
        Registers a payment against an already issued invoice, settling the
        outstanding balance. When the amount is omitted, the full outstanding
        balance is settled. Unlike updating an invoice, this operation is
        allowed on already issued documents. Only for INVOICE or DEBIT_NOTE
        documents in the ISSUED state.
      operationId: InvoicesController_pay
      parameters:
        - name: id
          required: true
          in: path
          description: Unique invoice identifier
          schema:
            example: 68483e978073231c3947077c
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PayInvoiceDto'
      responses:
        '200':
          description: Payment registered successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PayInvoiceResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Invoice not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Register invoice payment
      tags:
        - Invoices
  /invoices/{id}/cancel:
    post:
      description: >-
        Cancels an already issued invoice (and, when applicable, with the AT —
        the Portuguese Tax Authority). An invoice that already has issued
        credit/debit notes cannot be cancelled.
      operationId: InvoicesController_cancel
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      responses:
        '200':
          description: Invoice cancelled successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CancelInvoiceResponseDto'
        '400':
          description: Cannot cancel (already cancelled or has issued credit/debit notes)
        '401':
          description: Unauthorized - API key missing or invalid
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Cancel issued invoice
      tags:
        - Invoices
  /invoices/{id}/pdf:
    get:
      description: Generates and returns the download link for an invoice PDF
      operationId: InvoicesController_getPdf
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: isDuplicate
          required: false
          in: query
          description: Mark PDF as duplicate
          schema:
            default: false
            example: false
            type: boolean
        - name: format
          required: false
          in: query
          description: PDF format
          schema:
            enum:
              - A4
              - RECEIPT
              - RECEIPT_58
            type: string
        - name: templateId
          required: false
          in: query
          description: ID of the template to use
          schema:
            example: ''
            type: string
      responses:
        '200':
          description: PDF generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DownloadInvoicePdfResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Invoice not found
      security:
        - x-api-key: []
        - bearer: []
      summary: Download invoice PDF
      tags:
        - Invoices
  /transport-documents:
    post:
      description: >-
        Creates a draft transport document without issuing it or reporting it to
        the AT. Use POST /transport-documents/{id}/issue to issue and report it
        to the AT.
      operationId: TransportDocumentsController_create
      parameters:
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: Data required to create the draft transport document
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateTransportDocumentDto'
      responses:
        '201':
          description: Draft transport document created successfully
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
      summary: Create draft transport document
      tags:
        - Transport Documents
    get:
      description: >-
        Returns a paginated, filterable list of transport documents. By default
        returns 20 documents starting at offset 0.
      operationId: TransportDocumentsController_findAll
      parameters:
        - name: offset
          required: false
          in: query
          description: Number of records to skip (offset)
          schema:
            default: 0
            example: 0
            type: number
        - name: limit
          required: false
          in: query
          description: Maximum number of records to return
          schema:
            default: 20
            example: 20
            type: number
        - name: sort
          required: false
          in: query
          description: Sort field and order (e.g. movementDate:desc)
          schema:
            example: movementDate:desc
            type: string
        - name: search
          required: false
          in: query
          description: Global search term (number, recipient, etc.)
          schema:
            example: GT
            type: string
        - name: movementType
          required: false
          in: query
          description: Filter by movement type
          schema:
            example: GUIA_DE_REMESSA
            type: string
            enum:
              - GUIA_DE_ATIVOS_PROPRIOS
              - GUIA_DE_CONSIGNACAO
              - GUIA_DE_DEVOLUCAO
              - GUIA_DE_REMESSA
              - GUIA_DE_TRANSPORTE
        - name: issueStatus
          required: false
          in: query
          description: Filter by issue status
          schema:
            example: ISSUED
            type: string
            enum:
              - CANCELED
              - DRAFT
              - ISSUED
      responses:
        '200':
          description: List of transport documents returned successfully
        '400':
          description: Invalid parameters
        '401':
          description: Unauthorized - API key missing or invalid
      security:
        - x-api-key: []
      summary: List transport documents
      tags:
        - Transport Documents
  /transport-documents/{id}:
    patch:
      description: >-
        Updates a draft transport document. Only the sent fields are changed.
        Only draft (DRAFT) transport documents can be updated.
      operationId: TransportDocumentsController_update
      parameters:
        - name: id
          required: true
          in: path
          description: Transport document identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: Fields to update
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateTransportDocumentDto'
      responses:
        '200':
          description: Transport document updated successfully
        '400':
          description: Invalid data or transport document already issued
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Transport document not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
      summary: Update draft transport document
      tags:
        - Transport Documents
    get:
      description: >-
        Returns a transport document, including ATCUD, document number and the
        AT communication status (syncWithAt).
      operationId: TransportDocumentsController_findOne
      parameters:
        - name: id
          required: true
          in: path
          description: Transport document identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
      responses:
        '200':
          description: Transport document found
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Transport document not found
      security:
        - x-api-key: []
      summary: Get transport document by ID
      tags:
        - Transport Documents
    delete:
      description: >-
        Deletes a draft transport document. Already issued documents cannot be
        deleted — use POST /transport-documents/{id}/cancel to cancel them.
      operationId: TransportDocumentsController_delete
      parameters:
        - name: id
          required: true
          in: path
          description: Transport document identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      responses:
        '200':
          description: Transport document deleted successfully
        '400':
          description: Transport document already issued — cannot be deleted
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Transport document not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
      summary: Delete draft transport document
      tags:
        - Transport Documents
  /transport-documents/{id}/issue:
    post:
      description: >-
        Issues the transport document and reports it to the AT. The document
        becomes ISSUED and receives a document number and ATCUD. The AT
        communication status is returned in "syncWithAt" (PROCESSING, SYNCED or
        FAILED). Reporting to the AT requires the account to have AT
        synchronization enabled and validated credentials.
      operationId: TransportDocumentsController_issue
      parameters:
        - name: id
          required: true
          in: path
          description: Transport document identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      responses:
        '200':
          description: Transport document issued successfully
        '400':
          description: Transport document invalid or already issued
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Transport document not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
      summary: Issue transport document
      tags:
        - Transport Documents
  /transport-documents/{id}/cancel:
    post:
      description: >-
        Cancels an already issued transport document and reports the
        cancellation to the AT. The document becomes CANCELED. Only issued
        (ISSUED) transport documents can be cancelled.
      operationId: TransportDocumentsController_cancel
      parameters:
        - name: id
          required: true
          in: path
          description: Transport document identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      responses:
        '200':
          description: Transport document cancelled successfully
        '400':
          description: Transport document not issued or already cancelled
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Transport document not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
      summary: Cancel transport document
      tags:
        - Transport Documents
  /transport-documents/{id}/pdf:
    get:
      description: >-
        Generates and returns the download link for a transport document PDF.
        The PDF includes the QR code and the ATCUD, as required by the AT.
      operationId: TransportDocumentsController_getPdf
      parameters:
        - name: id
          required: true
          in: path
          description: Transport document identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: isDuplicate
          required: false
          in: query
          description: Mark PDF as duplicate
          schema:
            default: false
            example: false
            type: boolean
      responses:
        '200':
          description: PDF generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DownloadTransportDocumentPdfResponseDto'
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Transport document not found
      security:
        - x-api-key: []
      summary: Download transport document PDF
      tags:
        - Transport Documents
  /proposals:
    post:
      description: >-
        Creates a pro forma (commercial proposal). A pro forma is numbered
        immediately (PF …), is not reported to the AT and has no fiscal effect.
        It stays CREATED until it is converted into an invoice in the FIZ app
        (ISSUED) or canceled (CANCELED).
      operationId: ProposalsController_create
      parameters:
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: Data required to create the pro forma
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateProposalDto'
      responses:
        '201':
          description: Pro forma created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProposalResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
      summary: Create pro forma
      tags:
        - Pro formas
    get:
      description: >-
        Returns a list of pro formas with pagination and filters. By default,
        returns 20 records starting at offset 0.
      operationId: ProposalsController_findAll
      parameters:
        - name: offset
          required: false
          in: query
          description: Number of records to skip (offset)
          schema:
            default: 0
            example: 0
            type: number
        - name: limit
          required: false
          in: query
          description: Maximum number of records to return
          schema:
            default: 20
            example: 20
            type: number
        - name: sort
          required: false
          in: query
          description: Sort field and order (e.g. date:desc, number:asc)
          schema:
            example: date:desc
            type: string
        - name: search
          required: false
          in: query
          description: Global search term (number, customer, etc.)
          schema:
            example: PF
            type: string
        - name: status
          required: false
          in: query
          description: Filter by status
          schema:
            example: CREATED
            type: string
            enum:
              - CANCELED
              - CREATED
              - ISSUED
              - PROCESSING
        - name: fromDate
          required: false
          in: query
          description: Filter from this date (ISO 8601 with timezone)
          schema:
            example: '2025-01-01T00:00:00.000Z'
            type: string
        - name: toDate
          required: false
          in: query
          description: Filter up to this date (ISO 8601 with timezone)
          schema:
            example: '2025-12-31T23:59:59.999Z'
            type: string
      responses:
        '200':
          description: List of pro formas returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/ProposalResponseDto'
        '400':
          description: Invalid parameters
        '401':
          description: Unauthorized - API key missing or invalid
      security:
        - x-api-key: []
      summary: List pro formas
      tags:
        - Pro formas
  /proposals/{id}:
    get:
      description: >-
        Returns a pro forma with its lines, totals and the invoices raised from
        it (relatedDocuments).
      operationId: ProposalsController_findOne
      parameters:
        - name: id
          required: true
          in: path
          description: Pro forma identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
      responses:
        '200':
          description: Pro forma found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProposalResponseDto'
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Pro forma not found
      security:
        - x-api-key: []
      summary: Get pro forma by ID
      tags:
        - Pro formas
    delete:
      description: >-
        Permanently deletes an active (CREATED) or canceled (CANCELED) pro
        forma. A pro forma converted into an invoice (ISSUED) cannot be deleted,
        because the invoice references it.
      operationId: ProposalsController_delete
      parameters:
        - name: id
          required: true
          in: path
          description: Pro forma identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      responses:
        '200':
          description: Pro forma deleted successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeleteProposalResponseDto'
        '400':
          description: Pro forma converted into an invoice — cannot be deleted
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Pro forma not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
      summary: Delete pro forma
      tags:
        - Pro formas
  /proposals/{id}/cancel:
    post:
      description: >-
        Cancels an active (CREATED) pro forma. The pro forma becomes CANCELED
        and stays in the history. A pro forma already converted into an invoice
        (ISSUED) cannot be canceled.
      operationId: ProposalsController_cancel
      parameters:
        - name: id
          required: true
          in: path
          description: Pro forma identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      responses:
        '200':
          description: Pro forma canceled successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProposalResponseDto'
        '400':
          description: Pro forma already converted into an invoice or already canceled
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Pro forma not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
      summary: Cancel pro forma
      tags:
        - Pro formas
  /proposals/{id}/pdf:
    get:
      description: Generates and returns the download link for the PDF of a pro forma.
      operationId: ProposalsController_getPdf
      parameters:
        - name: id
          required: true
          in: path
          description: Pro forma identifier
          schema:
            example: 6900afc7e9a04d2adc897c68
            type: string
        - name: isDuplicate
          required: false
          in: query
          description: Mark PDF as duplicate
          schema:
            default: false
            example: false
            type: boolean
        - name: templateId
          required: false
          in: query
          description: ID of the template to use
          schema:
            example: ''
            type: string
      responses:
        '200':
          description: PDF generated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DownloadProposalPdfResponseDto'
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Pro forma not found
      security:
        - x-api-key: []
      summary: Download pro forma PDF
      tags:
        - Pro formas
  /customers:
    post:
      description: Creates a new customer in the system
      operationId: CustomersController_create
      parameters:
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: Data required to create the customer
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateCustomerDto'
      responses:
        '201':
          description: Customer created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateCustomerResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Create customer
      tags:
        - Customers
    get:
      description: >-
        Returns a paginated, filterable list of customers. By default returns 20
        customers starting at offset 0.
      operationId: CustomersController_findAll
      parameters:
        - name: offset
          required: false
          in: query
          description: Number of records to skip (offset)
          schema:
            default: 0
            example: 0
            type: number
        - name: limit
          required: false
          in: query
          description: Maximum number of records to return
          schema:
            default: 20
            example: 20
            type: number
        - name: sort
          required: false
          in: query
          description: Sort field and order (e.g. name:asc, city:desc)
          schema:
            example: name:asc
            type: string
        - name: search
          required: false
          in: query
          description: Global search term
          schema:
            example: Silva
            type: string
        - name: taxpayerNumber
          required: false
          in: query
          description: Filter by tax number (NIF)
          schema:
            example: '303741791'
            type: string
        - name: name
          required: false
          in: query
          description: Filter by name
          schema:
            example: João Silva
            type: string
        - name: firstName
          required: false
          in: query
          description: Filter by first name
          schema:
            example: João
            type: string
        - name: lastName
          required: false
          in: query
          description: Filter by last name
          schema:
            example: Silva
            type: string
        - name: companyName
          required: false
          in: query
          description: Filter by company name
          schema:
            example: Silva & Associados Lda
            type: string
        - name: companyPosition
          required: false
          in: query
          description: Filter by position in the company
          schema:
            example: Diretor Geral
            type: string
        - name: email
          required: false
          in: query
          description: Filter by email
          schema:
            example: joao.silva@example.com
            type: string
        - name: website
          required: false
          in: query
          description: Filter by website
          schema:
            example: https://example.com
            type: string
        - name: description
          required: false
          in: query
          description: Filter by description
          schema:
            example: Cliente VIP
            type: string
        - name: address
          required: false
          in: query
          description: Filter by address
          schema:
            example: Rua das Flores
            type: string
        - name: postalCode
          required: false
          in: query
          description: Filter by postal code
          schema:
            example: 1000-100
            type: string
        - name: country
          required: false
          in: query
          description: Filter by country
          schema:
            example: PT
            type: string
        - name: phone
          required: false
          in: query
          description: Filter by phone
          schema:
            example: '+351912345678'
            type: string
        - name: fax
          required: false
          in: query
          description: Filter by fax
          schema:
            example: '+351212345678'
            type: string
        - name: mobile
          required: false
          in: query
          description: Filter by mobile phone
          schema:
            example: '+351912345678'
            type: string
        - name: city
          required: false
          in: query
          description: Filter by city
          schema:
            example: Lisboa
            type: string
        - name: system
          required: false
          in: query
          description: Filter by system type
          schema:
            example: false
            type: boolean
        - name: isArchived
          required: false
          in: query
          description: Filter by archived status
          schema:
            example: false
            type: boolean
      responses:
        '200':
          description: List of customers returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CreateCustomerResponseDto'
        '400':
          description: Invalid parameters
        '401':
          description: Unauthorized - API key missing or invalid
      security:
        - x-api-key: []
        - bearer: []
      summary: List customers
      tags:
        - Customers
  /customers/{id}:
    get:
      description: Returns a single customer by its unique identifier
      operationId: CustomersController_findOne
      parameters:
        - name: id
          required: true
          in: path
          description: Unique customer identifier
          schema:
            example: 6863b1513117c5892ff55296
            type: string
      responses:
        '200':
          description: Customer found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateCustomerResponseDto'
        '400':
          description: Invalid ID
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Customer not found
      security:
        - x-api-key: []
        - bearer: []
      summary: Get customer by ID
      tags:
        - Customers
    patch:
      description: Updates an existing customer
      operationId: CustomersController_update
      parameters:
        - name: id
          required: true
          in: path
          description: Unique customer identifier
          schema:
            example: 6863b1513117c5892ff55296
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: Customer fields to update
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateCustomerDto'
      responses:
        '200':
          description: Customer updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateCustomerResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Update customer
      tags:
        - Customers
    delete:
      description: >-
        Archives a customer by its unique identifier. The customer is not
        permanently removed, only marked as archived.
      operationId: CustomersController_delete
      parameters:
        - name: id
          required: true
          in: path
          description: Unique customer identifier
          schema:
            example: 6863b1513117c5892ff55296
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      responses:
        '200':
          description: Customer archived successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateCustomerResponseDto'
        '400':
          description: Invalid ID
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Customer not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Archive customer
      tags:
        - Customers
  /items:
    post:
      description: Creates a new item/product in the system
      operationId: ItemsController_create
      parameters:
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: Data required to create the item
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateItemDto'
      responses:
        '201':
          description: Item created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateItemResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Create item
      tags:
        - Items
    get:
      description: >-
        Returns a paginated, filterable list of items. By default returns 20
        items starting at offset 0.
      operationId: ItemsController_findAll
      parameters:
        - name: offset
          required: false
          in: query
          description: Number of records to skip (offset)
          schema:
            default: 0
            example: 0
            type: number
        - name: limit
          required: false
          in: query
          description: Maximum number of records to return
          schema:
            default: 20
            example: 20
            type: number
        - name: sort
          required: false
          in: query
          description: Sort field and order (e.g. name:asc, unitPrice:desc)
          schema:
            example: name:asc
            type: string
        - name: search
          required: false
          in: query
          description: Global search term
          schema:
            example: TV
            type: string
        - name: name
          required: false
          in: query
          description: Filter by name
          schema:
            example: TV LG
            type: string
        - name: type
          required: false
          in: query
          description: Filter by type
          schema:
            example: PRODUCT
            type: string
            enum:
              - PRODUCT
              - SERVICE
        - name: unitPrice
          required: false
          in: query
          description: Filter by unit price
          schema:
            example: 1500
            type: number
        - name: unitType
          required: false
          in: query
          description: Filter by unit type
          schema:
            example: UNIT
            type: string
            enum:
              - BOX
              - CUBIC_METER
              - DAY
              - HOUR
              - KILOGRAM
              - LITER
              - METER
              - MONTH
              - NA
              - PACKAGE
              - SQUARE_METER
              - UNIT
              - WEEK
        - name: taxRate
          required: false
          in: query
          description: Filter by tax rate
          schema:
            example: 23
            type: number
        - name: vatRate
          required: false
          in: query
          description: Filter by VAT rate
          schema:
            example: NORMAL
            type: string
            enum:
              - EXEMPT
              - INTERMEDIATE
              - NORMAL
              - REDUCED
        - name: vatExemptionReason
          required: false
          in: query
          description: Filter by VAT exemption reason
          schema:
            example: M01
            type: string
        - name: withholdingTaxPercent
          required: false
          in: query
          description: Filter by withholding tax percentage
          schema:
            example: 25
            type: number
        - name: withholdingTaxType
          required: false
          in: query
          description: Filter by withholding tax type
          schema:
            example: IRS
            type: string
            enum:
              - IRC
              - IRS
              - IS
        - name: withholdingTaxAvailable
          required: false
          in: query
          description: Filter by withholding tax availability
          schema:
            example: true
            type: boolean
        - name: withholdingTaxReason
          required: false
          in: query
          description: Filter by withholding tax reason
          schema:
            example: Serviços profissionais
            type: string
        - name: isArchived
          required: false
          in: query
          description: Filter by archived status
          schema:
            example: false
            type: boolean
        - name: vatTerritory
          required: false
          in: query
          description: Filter by VAT territory
          schema:
            example: CONTINENTAL
            type: string
            enum:
              - AZORES
              - CONTINENTAL
              - MADEIRA
              - UNKNOWN
        - name: isAutoVATEnabled
          required: false
          in: query
          description: Filter by automatic VAT enabled
          schema:
            example: false
            type: boolean
      responses:
        '200':
          description: List of items returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CreateItemResponseDto'
        '400':
          description: Invalid parameters
        '401':
          description: Unauthorized - API key missing or invalid
      security:
        - x-api-key: []
        - bearer: []
      summary: List items
      tags:
        - Items
  /items/{id}:
    get:
      description: Returns a single item by its unique identifier
      operationId: ItemsController_findOne
      parameters:
        - name: id
          required: true
          in: path
          description: Unique item identifier
          schema:
            example: 68483e978073231c3947077c
            type: string
      responses:
        '200':
          description: Item found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateItemResponseDto'
        '400':
          description: Invalid ID
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Item not found
      security:
        - x-api-key: []
        - bearer: []
      summary: Get item by ID
      tags:
        - Items
    patch:
      description: Updates an existing item/product
      operationId: ItemsController_update
      parameters:
        - name: id
          required: true
          in: path
          description: Unique item identifier
          schema:
            example: 68483e978073231c3947077c
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      requestBody:
        required: true
        description: Item fields to update
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateItemDto'
      responses:
        '200':
          description: Item updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateItemResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Update item
      tags:
        - Items
    delete:
      description: >-
        Archives an item by its unique identifier. The item is not permanently
        removed, only marked as archived.
      operationId: ItemsController_delete
      parameters:
        - name: id
          required: true
          in: path
          description: Unique item identifier
          schema:
            example: 68483e978073231c3947077c
            type: string
        - name: idempotency-key
          in: header
          description: >-
            Optional idempotency key (a UUID, say). Retrying the request with
            the same key returns the original response instead of executing it
            again. At most 128 printable ASCII characters.
          required: false
          schema:
            type: string
            maxLength: 128
      responses:
        '200':
          description: Item archived successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreateItemResponseDto'
        '400':
          description: Invalid ID
        '401':
          description: Unauthorized - API key missing or invalid
        '404':
          description: Item not found
        '409':
          description: >-
            A request with this idempotency key is still being processed, or the
            outcome of the first attempt is unknown
        '422':
          description: The idempotency key was already used with a different request body
      security:
        - x-api-key: []
        - bearer: []
      summary: Archive item
      tags:
        - Items
  /templates:
    get:
      description: Returns a list of all templates available to the tenant.
      operationId: TemplatesController_getAll
      parameters: []
      responses:
        '200':
          description: List of templates returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/GetTemplatesResponseDto'
        '401':
          description: Unauthorized - API key missing or invalid
      security:
        - x-api-key: []
      summary: List templates
      tags:
        - PDF Templates
  /series:
    get:
      description: >-
        Returns the account's active series. Use the "id" field as "seriesId"
        when creating an invoice to issue it in a specific series.
      operationId: SeriesController_getAll
      parameters: []
      responses:
        '200':
          description: List of series returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/GetSeriesResponseDto'
        '401':
          description: Unauthorized - API key missing or invalid
      security:
        - x-api-key: []
        - bearer: []
      summary: List series
      tags:
        - Series
  /bank/connections:
    get:
      description: >-
        Returns the account's bank connections (open banking). Use the "id"
        field as connectionId when listing transactions.
      operationId: BankController_getConnections
      parameters: []
      responses:
        '200':
          description: List of connections returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                      example: a1b2c3d4-0000-0000-0000-000000000000
                    providerName:
                      type: string
                      example: Caixa Geral de Depósitos
                    countryCode:
                      type: string
                      example: PT
                    status:
                      type: string
                      example: active
                    createdAt:
                      type: string
                      format: date-time
                    updatedAt:
                      type: string
                      format: date-time
                    maskedIbans:
                      type: array
                      items:
                        type: string
                        example: PT··3003
        '401':
          description: Unauthorized - API key missing or invalid
        '403':
          description: No access to the bookkeeping feature
      security:
        - x-api-key: []
      summary: List bank connections
      tags:
        - Bank
  /bank/transactions:
    get:
      description: >-
        Returns the bank transactions (open banking) of a connection. The
        connectionId parameter is required — get it from GET /bank/connections.
      operationId: BankController_getTransactions
      parameters:
        - name: connectionId
          required: true
          in: query
          description: Bank connection identifier (obtained from GET /bank/connections)
          schema:
            example: a1b2c3d4-0000-0000-0000-000000000000
            type: string
        - name: page
          required: false
          in: query
          description: Page number (starts at 1)
          schema:
            default: 1
            example: 1
            type: number
        - name: pageSize
          required: false
          in: query
          description: Maximum number of records per page
          schema:
            default: 50
            example: 50
            type: number
        - name: fromDate
          required: false
          in: query
          description: Filter from this date (ISO 8601 with timezone)
          schema:
            example: '2025-01-01T00:00:00.000Z'
            type: string
        - name: toDate
          required: false
          in: query
          description: Filter up to this date (ISO 8601 with timezone)
          schema:
            example: '2025-12-31T23:59:59.999Z'
            type: string
        - name: searchString
          required: false
          in: query
          description: Global search term (description, merchant, etc.)
          schema:
            example: continente
            type: string
        - name: direction
          required: false
          in: query
          description: Filter by direction (incoming/outgoing)
          schema:
            example: Expense
            type: string
            enum:
              - Income
              - Expense
        - name: types
          required: false
          in: query
          description: Filter by transaction types
          schema:
            type: array
            items:
              type: string
              enum:
                - Purchase
                - Transfer
                - MbwayTransfer
                - Withdrawal
                - Fee
                - Other
        - name: language
          required: false
          in: query
          description: Language for category names (pt or en)
          schema:
            default: pt
            example: pt
            type: string
            enum:
              - pt
              - en
      responses:
        '200':
          description: List of transactions returned successfully
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  properties:
                    id:
                      type: string
                      example: txn_123
                    connectionId:
                      type: string
                      example: a1b2c3d4-...
                    amount:
                      type: number
                      example: -42.5
                    currency:
                      type: string
                      example: EUR
                    transactionDate:
                      type: string
                      format: date-time
                      example: '2025-03-14T09:21:00.000Z'
                    description:
                      type: string
                      example: Continente Lisboa
                    merchantName:
                      type: string
                      example: Continente
                    accountingCategoryName:
                      type: string
                      example: Alimentação
                    statusCode:
                      type: string
                      example: C
                    type:
                      type: string
                      example: Purchase
                    isPending:
                      type: boolean
                      example: false
        '400':
          description: Invalid parameters (e.g. missing connectionId)
        '401':
          description: Unauthorized - API key missing or invalid
        '403':
          description: No access to the bookkeeping feature
      security:
        - x-api-key: []
      summary: List bank transactions
      tags:
        - Bank
  /vat/calculate:
    post:
      description: >-
        Calculates the correct VAT rate for a sale based on the customer's
        country and type (B2C individual / B2B company), including OSS, reverse
        charge, intra-community exemption and the Portuguese territories. Does
        not create any invoice. Always returns the standard rate of the
        applicable regime (or 0% with the corresponding exemption reason);
        choosing reduced/intermediate rates per item category is the
        integrator's responsibility. Requires a plan with the Auto VAT feature.
      operationId: VatController_calculate
      parameters: []
      requestBody:
        required: true
        description: Customer and item data for the VAT calculation
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CalculateVatDto'
      responses:
        '200':
          description: VAT calculation performed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CalculateVatResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
        '402':
          description: >-
            Auto VAT feature not available on the current plan - upgrade
            required
      security:
        - x-api-key: []
      summary: Calculate VAT
      tags:
        - VAT
  /vat/validate-client:
    post:
      description: >-
        Verifies a customer's VAT number. For EU countries (except PT)
        validation is done via VIES (with a 24-hour cache); for PT and non-EU
        customers only the presence of a number is checked — the returned value
        does not guarantee the number exists. If VIES is unavailable, the
        provided clientHasVat value is returned. Does not create any record.
      operationId: VatController_validateClient
      parameters: []
      requestBody:
        required: true
        description: Customer data for VAT number verification
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ValidateClientVatDto'
      responses:
        '200':
          description: Verification performed successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidateClientVatResponseDto'
        '400':
          description: Invalid data
        '401':
          description: Unauthorized - API key missing or invalid
      security:
        - x-api-key: []
      summary: Verify customer VAT number
      tags:
        - VAT
  /company:
    get:
      operationId: CompanyController_getCompany
      parameters: []
      responses:
        '200':
          description: Connected company and preliminary issuance checks
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CompanyResponseDto'
      security:
        - x-api-key: []
        - bearer: []
      summary: Get company and issuance readiness
      tags:
        - Company
tags: []
servers: []
components:
  securitySchemes:
    x-api-key:
      type: apiKey
      in: header
      name: x-api-key
      description: >-
        API key for authentication. To get an API key go to
        https://app.fiz.co/settings/integrations.
    bearer:
      scheme: bearer
      bearerFormat: JWT
      type: http
  schemas:
    InvoiceItemDto:
      type: object
      properties:
        id:
          type: string
          description: Item identifier
          example: 68483e978073231c3947077c
        quantity:
          type: number
          description: Item quantity
          example: 1
          minimum: 1
        discountType:
          type: string
          description: >-
            Discount type for this line (optional). Overrides the discount set
            on the catalogue item. Applied before the invoice's global discount.
          enum:
            - AMOUNT
            - PERCENT
          example: PERCENT
        discountPercent:
          type: number
          description: >-
            Discount percentage for this line (e.g. 10 for 10%). Requires
            discountType=PERCENT.
          example: 10
          minimum: 0
          maximum: 100
        discountAmount:
          type: number
          description: >-
            Absolute per-unit discount amount for this line. Requires
            discountType=AMOUNT.
          example: 25
          minimum: 0
      required:
        - id
        - quantity
    InvoiceSummaryInputDto:
      type: object
      properties:
        globalDiscountType:
          type: string
          description: Global discount type
          enum:
            - AMOUNT
            - PERCENT
          example: PERCENT
        globalDiscountPercent:
          type: number
          description: Global discount percentage (e.g. 10 for 10%)
          example: 10
        globalDiscountAmount:
          type: number
          description: Absolute global discount amount
          example: 100
    InvoiceScheduleAutoSendEmailsDto:
      type: object
      properties:
        sendToCustomer:
          type: boolean
          description: Email the issued document to the customer
          example: true
        customerEmail:
          type: string
          description: >-
            Alternative customer email for the sending. If omitted, the email on
            the customer's record is used.
          example: faturas@cliente.pt
        sendToIssuer:
          type: boolean
          description: Send a copy of the issued document to the account's email
          example: false
    InvoiceScheduleInputDto:
      type: object
      properties:
        frequency:
          type: string
          description: >-
            Frequency. WEEKLY uses byDay; MONTHLY, QUARTERLY and ANNUALLY use
            byMonthDay. If omitted, the weekday / day of month of startDate
            applies.
          enum:
            - DAILY
            - WEEKLY
            - MONTHLY
            - QUARTERLY
            - ANNUALLY
          example: MONTHLY
        startDate:
          type: string
          description: >-
            First day the frequency is computed from (ISO 8601). The first
            document is issued on the first occurrence of the frequency from
            this date.
          example: '2026-10-01T00:00:00.000Z'
        endDate:
          type: string
          description: >-
            Last day a document may be issued on (ISO 8601). If omitted, issuing
            repeats until paused or deleted.
          example: '2027-09-30T00:00:00.000Z'
        timeOfDay:
          type: string
          description: >-
            Issuing time as HH:mm, in the account's timezone. If omitted, 12:00
            is used.
          example: '09:00'
          pattern: ^([01]\d|2[0-3]):[0-5]\d$
        byDay:
          description: >-
            Weekdays to issue on (0 = Monday … 6 = Sunday). Only with
            frequency=WEEKLY.
          example:
            - 0
          type: array
          items:
            type: number
        byMonthDay:
          description: >-
            Days of the month to issue on (1–31). Only with frequency=MONTHLY,
            QUARTERLY or ANNUALLY. A day the month lacks (31 in April) skips
            that month — use 28 or less to issue every month.
          example:
            - 1
          type: array
          items:
            type: number
        dueDateInDaysRange:
          type: number
          description: >-
            Due term in days, counted from each document's issue date. 0 (or
            omitted) = due on the same day.
          example: 30
          minimum: 0
        autoSend:
          type: boolean
          description: Email each issued document automatically, as set in autoSendEmails
          example: true
        autoSendEmails:
          description: Recipients of the automatic sending (only with autoSend=true)
          allOf:
            - $ref: '#/components/schemas/InvoiceScheduleAutoSendEmailsDto'
        name:
          type: string
          description: Internal schedule name (optional)
          example: Subscrição mensal — Leme
      required:
        - frequency
        - startDate
    CreateScheduledInvoiceDto:
      type: object
      properties:
        cae:
          type: string
          description: CAE code (Portuguese classification of economic activities)
          example: '1234'
        customerId:
          type: string
          description: Customer identifier
          example: 6863b1513117c5892ff55296
        seriesId:
          type: string
          description: >-
            Series identifier (optional). Use the "id" returned by GET /series.
            If omitted, the account's default series is used.
          example: 68483b3fa19e44171e3d0808
        notes:
          type: string
          description: Invoice notes (optional)
          example: Invoice 118
        items:
          description: List of invoice items
          example:
            - id: 68483e978073231c3947077c
              quantity: 1
              discountType: PERCENT
              discountPercent: 10
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemDto'
        summary:
          description: Invoice summary with global discount (optional)
          example:
            globalDiscountType: PERCENT
            globalDiscountPercent: 10
          allOf:
            - $ref: '#/components/schemas/InvoiceSummaryInputDto'
        schedule:
          description: Frequency and issuing options
          example:
            frequency: MONTHLY
            byMonthDay:
              - 1
            startDate: '2026-10-01T00:00:00.000Z'
            timeOfDay: '09:00'
            dueDateInDaysRange: 30
            autoSend: true
            autoSendEmails:
              sendToCustomer: true
          allOf:
            - $ref: '#/components/schemas/InvoiceScheduleInputDto'
      required:
        - cae
        - customerId
        - items
        - schedule
    SeriesDto:
      type: object
      properties:
        ref:
          type: string
          description: Series identifier
          example: 68483ba7a19e44171e3d080a
        name:
          type: string
          description: Series name
          example: FIZ20255de3d61a
      required:
        - ref
        - name
    CustomerDataDto:
      type: object
      properties:
        taxpayerNumber:
          type: string
          description: Tax number (NIF)
          example: '303741791'
        name:
          type: string
          description: Customer name
          example: Petr Kutis
        email:
          type: string
          description: Customer email
          example: test@test.com
        country:
          type: string
          description: Customer country
          example: PT
        phone:
          type: string
          description: Customer phone
          example: ''
      required:
        - taxpayerNumber
        - name
        - email
        - country
        - phone
    CustomerDto:
      type: object
      properties:
        ref:
          type: string
          description: Customer identifier
          example: 6863b1513117c5892ff55296
        data:
          description: Customer data
          allOf:
            - $ref: '#/components/schemas/CustomerDataDto'
      required:
        - ref
        - data
    InvoiceSummaryDto:
      type: object
      properties:
        amountWithoutTax:
          type: number
          description: Amount without tax
          example: 1500
        amountWithTax:
          type: number
          description: Amount with tax
          example: 1590
        amountWithoutTaxWithoutDiscount:
          type: object
          description: Amount without tax and discount
          example: 1500
          nullable: true
        taxAmount:
          type: number
          description: Tax amount
          example: 90
        globalDiscountType:
          type: string
          description: Global discount type
          enum:
            - AMOUNT
            - PERCENT
          example: null
          nullable: true
        globalDiscountPercent:
          type: object
          description: Global discount percentage
          example: null
          nullable: true
        globalDiscountAmount:
          type: object
          description: Global discount amount
          example: null
          nullable: true
        total:
          type: number
          description: Total
          example: 1590
        totalToPay:
          type: number
          description: Total payable
          example: 1590
        withholdingTaxAmount:
          type: object
          description: Withholding tax amount
          example: null
          nullable: true
        creditNotesTotal:
          type: object
          description: Total of credit notes
          example: null
          nullable: true
      required:
        - amountWithoutTax
        - amountWithTax
        - amountWithoutTaxWithoutDiscount
        - taxAmount
        - globalDiscountType
        - globalDiscountPercent
        - globalDiscountAmount
        - total
        - totalToPay
        - withholdingTaxAmount
        - creditNotesTotal
    ItemMetaDto:
      type: object
      properties:
        quantity:
          type: number
          description: Item quantity
          example: 1
        amountWithoutTax:
          type: number
          description: Amount without tax
          example: 1500
        amountWithTax:
          type: number
          description: Amount with tax
          example: 1590
        taxAmount:
          type: number
          description: Tax amount
          example: 90
        discountAmount:
          type: object
          description: Discount amount applied to the item
          example: 0
          nullable: true
        unitAmountWithoutTax:
          type: number
          description: Unit amount without tax
          example: 1500
        unitAmountWithTax:
          type: number
          description: Unit amount with tax
          example: 1590
        withholdingTaxAmount:
          type: object
          description: Withholding tax amount
          example: null
          nullable: true
        withholdingTaxEnabled:
          type: boolean
          description: Withholding tax enabled
          example: false
      required:
        - quantity
        - amountWithoutTax
        - amountWithTax
        - taxAmount
        - discountAmount
        - unitAmountWithoutTax
        - unitAmountWithTax
        - withholdingTaxAmount
        - withholdingTaxEnabled
    ItemDataDto:
      type: object
      properties:
        name:
          type: string
          description: Item name
          example: TV LG
        description:
          type: string
          description: Item description
          example: ''
        type:
          type: string
          description: Item type
          example: SERVICE
        unitPrice:
          type: number
          description: Unit price
          example: 1500
        taxRate:
          type: number
          description: Tax rate
          example: 6
        vatRate:
          type: string
          description: VAT rate
          example: REDUCED
        vatTerritory:
          type: string
          description: VAT territory
          example: CONTINENTAL
        vatExemptionReason:
          type: object
          description: VAT exemption reason
          example: null
          nullable: true
        isAutoVATEnabled:
          type: boolean
          description: Automatic VAT enabled
          example: false
      required:
        - name
        - description
        - type
        - unitPrice
        - taxRate
        - vatRate
        - vatTerritory
        - vatExemptionReason
        - isAutoVATEnabled
    InvoiceItemResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Identifier of the item on the invoice
          example: 6900afc77a570c16377ee6da
        ref:
          type: string
          description: Item reference
          example: 68483e978073231c3947077c
        meta:
          description: Item metadata
          allOf:
            - $ref: '#/components/schemas/ItemMetaDto'
        data:
          description: Item data
          allOf:
            - $ref: '#/components/schemas/ItemDataDto'
      required:
        - id
        - ref
        - meta
        - data
    InvoiceScheduleAutoSendEmailsResponseDto:
      type: object
      properties:
        sendToCustomer:
          type: object
          example: true
          nullable: true
        customerEmail:
          type: string
          example: null
          nullable: true
        sendToIssuer:
          type: object
          example: false
          nullable: true
      required:
        - sendToCustomer
        - customerEmail
        - sendToIssuer
    InvoiceScheduleResponseDto:
      type: object
      properties:
        status:
          type: string
          description: >-
            Schedule status. SCHEDULED issues on the next occurrence; PAUSED is
            on hold; COMPLETED reached endDate; FAILED stopped on an error (see
            failReason) and resumes with status=SCHEDULED.
          enum:
            - COMPLETED
            - FAILED
            - PAUSED
            - SCHEDULED
            - STOPPED
          example: SCHEDULED
        frequency:
          type: string
          description: >-
            Frequency. CUSTOM only appears on schedules created in the web app;
            the API does not accept it on create.
          enum:
            - ANNUALLY
            - CUSTOM
            - DAILY
            - MONTHLY
            - QUARTERLY
            - WEEKLY
          example: MONTHLY
        interval:
          type: object
          description: >-
            Interval between occurrences. Only has an effect with
            frequency=CUSTOM (schedules created in the web app); the API keeps
            it on update.
          example: 1
          nullable: true
        name:
          type: string
          description: Internal schedule name
          example: null
          nullable: true
        byDay:
          description: Weekdays (0 = Monday … 6 = Sunday)
          example: []
          type: array
          items:
            type: number
        byMonthDay:
          description: Days of the month (1–31)
          example:
            - 1
          type: array
          items:
            type: number
        timeOfDay:
          type: string
          description: Issuing time (HH:mm, account's timezone)
          example: '09:00'
        startDate:
          type: string
          description: Start of the frequency
          example: '2026-10-01T00:00:00.000Z'
        endDate:
          type: string
          description: End of the frequency
          example: null
          format: date-time
          nullable: true
        dueDateInDaysRange:
          type: object
          description: Due term in days
          example: 30
          nullable: true
        autoSend:
          type: object
          description: Automatic email sending
          example: true
          nullable: true
        autoSendEmails:
          description: Recipients of the automatic sending
          nullable: true
          allOf:
            - $ref: '#/components/schemas/InvoiceScheduleAutoSendEmailsResponseDto'
        nextRunAt:
          type: string
          description: >-
            Next planned issue. Null when there are no more occurrences
            (COMPLETED) or the schedule is stopped.
          example: '2026-11-01T09:00:00.000Z'
          format: date-time
          nullable: true
        failReason:
          type: string
          description: Reason for the last failure, when status=FAILED
          example: null
          nullable: true
      required:
        - status
        - frequency
        - interval
        - name
        - byDay
        - byMonthDay
        - timeOfDay
        - startDate
        - endDate
        - dueDateInDaysRange
        - autoSend
        - autoSendEmails
        - nextRunAt
        - failReason
    ScheduledInvoiceResponseDto:
      type: object
      properties:
        id:
          type: string
          description: >-
            Schedule ID. Also the scheduleTemplateId of the documents issued
            from it.
          example: 6900afc7e9a04d2adc897c68
        number:
          type: string
          description: >-
            Internal template reference (SCHED-0001, …). Not a fiscal number —
            each issued document gets its own number in the series.
          example: SCHED-0001
        documentType:
          type: string
          description: Document type to issue
          example: INVOICE
        status:
          type: string
          description: >-
            Template status — always SCHEDULED; the schedule status is in
            schedule.status
          example: SCHEDULED
        notes:
          type: string
          description: Notes copied to each document
          example: null
          nullable: true
        cae:
          type: string
          description: CAE code
          example: '1234'
        series:
          description: Series the documents are issued in
          nullable: true
          allOf:
            - $ref: '#/components/schemas/SeriesDto'
        customer:
          description: Customer
          allOf:
            - $ref: '#/components/schemas/CustomerDto'
        summary:
          description: Totals of each document to issue
          allOf:
            - $ref: '#/components/schemas/InvoiceSummaryDto'
        items:
          description: Items
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemResponseDto'
        schedule:
          description: Schedule
          allOf:
            - $ref: '#/components/schemas/InvoiceScheduleResponseDto'
        createdAt:
          type: string
          description: Creation date
          example: '2026-09-05T11:57:59.008Z'
        updatedAt:
          type: string
          description: Last change date
          example: '2026-09-05T11:57:59.008Z'
      required:
        - id
        - number
        - documentType
        - status
        - notes
        - cae
        - series
        - customer
        - summary
        - items
        - schedule
        - createdAt
        - updatedAt
    UpdateScheduledInvoiceDto:
      type: object
      properties:
        frequency:
          type: string
          description: >-
            Frequency. WEEKLY uses byDay; MONTHLY, QUARTERLY and ANNUALLY use
            byMonthDay. If omitted, the weekday / day of month of startDate
            applies.
          enum:
            - DAILY
            - WEEKLY
            - MONTHLY
            - QUARTERLY
            - ANNUALLY
          example: MONTHLY
        startDate:
          type: string
          description: >-
            First day the frequency is computed from (ISO 8601). The first
            document is issued on the first occurrence of the frequency from
            this date.
          example: '2026-10-01T00:00:00.000Z'
        timeOfDay:
          type: string
          description: >-
            Issuing time as HH:mm, in the account's timezone. If omitted, 12:00
            is used.
          example: '09:00'
          pattern: ^([01]\d|2[0-3]):[0-5]\d$
        byDay:
          description: >-
            Weekdays to issue on (0 = Monday … 6 = Sunday). Only with
            frequency=WEEKLY.
          example:
            - 0
          type: array
          items:
            type: number
        byMonthDay:
          description: >-
            Days of the month to issue on (1–31). Only with frequency=MONTHLY,
            QUARTERLY or ANNUALLY. A day the month lacks (31 in April) skips
            that month — use 28 or less to issue every month.
          example:
            - 1
          type: array
          items:
            type: number
        dueDateInDaysRange:
          type: number
          description: >-
            Due term in days, counted from each document's issue date. 0 (or
            omitted) = due on the same day.
          example: 30
          minimum: 0
        autoSend:
          type: boolean
          description: Email each issued document automatically, as set in autoSendEmails
          example: true
        autoSendEmails:
          description: Recipients of the automatic sending (only with autoSend=true)
          allOf:
            - $ref: '#/components/schemas/InvoiceScheduleAutoSendEmailsDto'
        name:
          type: string
          description: Internal schedule name (optional)
          example: Subscrição mensal — Leme
        status:
          type: string
          description: >-
            Pause (PAUSED) or (re)activate (SCHEDULED) the schedule. A FAILED or
            COMPLETED schedule only issues again after receiving SCHEDULED.
          enum:
            - SCHEDULED
            - PAUSED
          example: PAUSED
        endDate:
          type: string
          description: >-
            Last day a document may be issued on (ISO 8601). Send null to remove
            the end and repeat indefinitely. If omitted, the stored value is
            kept.
          example: '2027-09-30T00:00:00.000Z'
          format: date-time
          nullable: true
    DeleteInvoiceResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Unique invoice identifier
          example: 6900afc7e9a04d2adc897c68
        createdAt:
          type: string
          description: Invoice creation date
          example: '2025-10-28T11:57:59.008Z'
      required:
        - id
        - createdAt
    InvoicePaymentInputDto:
      type: object
      properties:
        method:
          type: string
          description: Payment method
          enum:
            - cash
            - card
            - bankTransfer
            - mbWay
            - multibanco
            - spin
            - other
          example: mbWay
        date:
          type: string
          description: Payment date
          example: '2025-11-04T07:00:00.000Z'
      required:
        - method
        - date
    CreateInvoiceDto:
      type: object
      properties:
        date:
          type: string
          description: >-
            Invoice issue date (optional). Defaults to the current date and time
            when omitted. Determines the tax period the document falls in.
          example: '2025-10-15T07:00:00.000Z'
        dueDate:
          type: string
          description: >-
            Invoice due date (optional). When omitted, the issue date is used —
            which is what is expected on documents settled on issue, such as an
            invoice-receipt.
          example: '2025-11-04T07:00:00.000Z'
        taxPointDate:
          type: string
          description: >-
            Date of supply: the date on which the goods were made available to
            the acquirer or on which the services were performed (art. 36.º n.º
            5 al. f) CIVA). Optional — when omitted, the issue date is used. It
            cannot be later than the issue date. On credit/debit notes it is
            ignored, since they inherit the date of supply of the original
            document.
          example: '2025-10-20T07:00:00.000Z'
        cae:
          type: string
          description: CAE code (Portuguese classification of economic activities)
          example: '1234'
        type:
          type: string
          description: Document type
          enum:
            - CREDIT_NOTE
            - DEBIT_NOTE
            - INVOICE
            - INVOICE_RECEIPT
            - RECEIPT
            - SIMPLIFIED_INVOICE
          example: INVOICE
        customerId:
          type: string
          description: Customer identifier
          example: 6863b1513117c5892ff55296
        seriesId:
          type: string
          description: >-
            Series identifier (optional). Use the "id" returned by GET /series.
            If omitted, the account's default series is used.
          example: 68483b3fa19e44171e3d0808
        notes:
          type: string
          description: Invoice notes (optional)
          example: Invoice 118
        items:
          description: List of invoice items
          example:
            - id: 68483e978073231c3947077c
              quantity: 1
              discountType: PERCENT
              discountPercent: 10
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemDto'
        summary:
          description: Invoice summary with global discount (optional)
          example:
            globalDiscountType: PERCENT
            globalDiscountPercent: 10
          allOf:
            - $ref: '#/components/schemas/InvoiceSummaryInputDto'
        payment:
          description: >-
            Payment (optional). Only allowed for the INVOICE_RECEIPT and
            SIMPLIFIED_INVOICE types.
          example:
            method: mbWay
            date: '2025-11-04T07:00:00.000Z'
          allOf:
            - $ref: '#/components/schemas/InvoicePaymentInputDto'
      required:
        - cae
        - type
        - customerId
        - items
    CreateInvoiceResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Unique invoice identifier
          example: 6900afc7e9a04d2adc897c68
        number:
          type: string
          description: Document number. Null on a draft — it is assigned on issue.
          example: null
          nullable: true
        atcud:
          type: string
          description: >-
            Unique document code (ATCUD). Null on a draft — it is assigned on
            issue.
          example: null
          nullable: true
        shortHash:
          type: string
          description: >-
            Document hash summary (4 characters). Null on a draft — it is
            assigned on issue.
          example: null
          nullable: true
        documentType:
          type: string
          description: Document type
          example: INVOICE
        status:
          type: string
          description: Invoice status
          example: ISSUED
        notes:
          type: object
          description: Invoice notes
          example: null
          nullable: true
        series:
          description: Invoice series
          allOf:
            - $ref: '#/components/schemas/SeriesDto'
        payment:
          type: object
          description: Payment
          example: null
          nullable: true
        customer:
          description: Customer
          allOf:
            - $ref: '#/components/schemas/CustomerDto'
        dueDate:
          type: string
          description: Invoice due date
          example: '2025-11-04T07:00:00.000Z'
        date:
          type: string
          description: Invoice issue date
          example: '2025-10-28T11:57:59.008Z'
        taxPointDate:
          type: string
          description: >-
            Date of supply, when recorded (art. 36.º n.º 5 al. f) CIVA). Comes
            back null when it was not recorded — the issue date applies in that
            case.
          example: '2025-10-20T07:00:00.000Z'
          format: date-time
          nullable: true
        items:
          description: Invoice items
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemResponseDto'
      required:
        - id
        - number
        - atcud
        - shortHash
        - documentType
        - status
        - notes
        - series
        - payment
        - customer
        - dueDate
        - date
        - taxPointDate
        - items
    CreateCreditNoteDto:
      type: object
      properties:
        parentInvoiceId:
          type: string
          description: >-
            Identifier of the invoice to reverse (the credit note reverses this
            document). The items and the customer are copied from this invoice
            (full reversal).
          example: 6900afc7e9a04d2adc897c68
        reasonCode:
          type: string
          description: Credit note reason (Annex 40 / Art. 78 of the Portuguese VAT Code)
          enum:
            - ACCOUNTING_SYNC_ERROR
            - BAD_DEBT_UNDER_750
            - CORPORATE_REORGANIZATION
            - DEATH_NO_ASSETS
            - DEDUCTION_RIGHT_ALTERATION
            - DEDUCTION_RIGHT_CHANGE
            - DISCOUNT_BONUS
            - FINAL_CREDIT_REDUCTION
            - FIXED_ASSET_REGULARIZATION
            - INCORRECT_VAT_RATE
            - INSOLVENCY_CLOSED
            - INVOICE_EMISSION_ERROR
            - LEGAL_PROVISION_CHANGE
            - MERGER_INCORPORATION
            - OPERATION_CANCELLATION
            - OTHER_LEGAL_REGULARIZATIONS
            - PROPERTY_OUT_OF_BUSINESS
            - PRORATA_ADJUSTMENT
            - RATEIO_FINAL_NO_PAYMENT
            - REAL_AFFECTATION_CHANGE
            - RETURN_GOODS_SERVICES
            - SPLIT_PATRIMONY_TRANSFER
            - TAX_RATE_CHANGE
            - TECHNICAL_CORRECTION
            - VAT_REGIME_CHANGE
            - VAT_REGIME_CHANGE_ART25
            - WRONG_INVOICE
          example: INCORRECT_VAT_RATE
        reason:
          type: string
          description: >-
            Text description of the reason (required). If omitted, the
            reasonCode's default description is used.
          example: Correção de IVA — taxa incorreta
        issue:
          type: boolean
          description: >-
            Issue the credit note immediately (true) or leave it as a draft
            (false). Issued by default.
          example: true
          default: true
      required:
        - parentInvoiceId
        - reasonCode
    CreateCreditNoteResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Unique credit note identifier
          example: 6900afc7e9a04d2adc897c68
        documentType:
          type: string
          description: Document type
          example: CREDIT_NOTE
        status:
          type: string
          description: Document status
          example: ISSUED
        creditNoteReasonCode:
          type: string
          description: Credit note reason
          enum:
            - ACCOUNTING_SYNC_ERROR
            - BAD_DEBT_UNDER_750
            - CORPORATE_REORGANIZATION
            - DEATH_NO_ASSETS
            - DEDUCTION_RIGHT_ALTERATION
            - DEDUCTION_RIGHT_CHANGE
            - DISCOUNT_BONUS
            - FINAL_CREDIT_REDUCTION
            - FIXED_ASSET_REGULARIZATION
            - INCORRECT_VAT_RATE
            - INSOLVENCY_CLOSED
            - INVOICE_EMISSION_ERROR
            - LEGAL_PROVISION_CHANGE
            - MERGER_INCORPORATION
            - OPERATION_CANCELLATION
            - OTHER_LEGAL_REGULARIZATIONS
            - PROPERTY_OUT_OF_BUSINESS
            - PRORATA_ADJUSTMENT
            - RATEIO_FINAL_NO_PAYMENT
            - REAL_AFFECTATION_CHANGE
            - RETURN_GOODS_SERVICES
            - SPLIT_PATRIMONY_TRANSFER
            - TAX_RATE_CHANGE
            - TECHNICAL_CORRECTION
            - VAT_REGIME_CHANGE
            - VAT_REGIME_CHANGE_ART25
            - WRONG_INVOICE
          example: INCORRECT_VAT_RATE
        parentInvoiceId:
          type: string
          description: Identifier of the reversed invoice
          example: 6900afc7e9a04d2adc897c68
        parentInvoiceNumber:
          type: object
          description: Number of the reversed invoice
          example: FR FIZ2026/336
          nullable: true
        taxPointDate:
          type: string
          description: >-
            Date of supply, when recorded (art. 36.º n.º 5 al. f) CIVA). Comes
            back null when it was not recorded — the issue date applies in that
            case.
          example: '2025-10-20T07:00:00.000Z'
          format: date-time
          nullable: true
        customer:
          description: Customer
          allOf:
            - $ref: '#/components/schemas/CustomerDto'
        items:
          description: Credit note items
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemResponseDto'
        summary:
          description: Document summary
          allOf:
            - $ref: '#/components/schemas/InvoiceSummaryDto'
      required:
        - id
        - documentType
        - status
        - creditNoteReasonCode
        - parentInvoiceId
        - parentInvoiceNumber
        - taxPointDate
        - customer
        - items
        - summary
    UpdateInvoiceDto:
      type: object
      properties:
        date:
          type: string
          description: >-
            Invoice issue date. When omitted, the date already stored on the
            invoice is kept. Determines the tax period the document falls in.
          example: '2025-10-15T07:00:00.000Z'
        dueDate:
          type: string
          description: >-
            Invoice due date (optional). When omitted, the issue date is used —
            which is what is expected on documents settled on issue, such as an
            invoice-receipt.
          example: '2025-11-04T07:00:00.000Z'
        cae:
          type: string
          description: CAE code (Portuguese classification of economic activities)
          example: '1234'
        customerId:
          type: string
          description: Customer identifier
          example: 6863b1513117c5892ff55296
        seriesId:
          type: string
          description: >-
            Series identifier (optional). Use the "id" returned by GET /series.
            If omitted, the account's default series is used.
          example: 68483b3fa19e44171e3d0808
        notes:
          type: string
          description: Invoice notes (optional)
          example: Invoice 118
        items:
          description: List of invoice items
          example:
            - id: 68483e978073231c3947077c
              quantity: 1
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemDto'
        summary:
          description: Invoice summary with global discount (optional)
          example:
            globalDiscountType: PERCENT
            globalDiscountPercent: 10
          allOf:
            - $ref: '#/components/schemas/InvoiceSummaryInputDto'
        taxPointDate:
          type: string
          description: >-
            Date of supply (art. 36.º n.º 5 al. f) CIVA). Send null to clear the
            recorded date and fall back to the issue date. If omitted, the date
            already stored on the invoice is kept.
          example: '2025-10-20T07:00:00.000Z'
          nullable: true
        payment:
          description: Payment
          example:
            method: mbWay
            date: '2025-11-04T07:00:00.000Z'
          allOf:
            - $ref: '#/components/schemas/InvoicePaymentInputDto'
    IssueInvoiceDto:
      type: object
      properties:
        expectedUpdatedAt:
          type: string
          description: >-
            Draft revision (updatedAt). Issuance is refused if the document has
            changed.
          format: date-time
    SyncWithAtDto:
      type: object
      properties:
        status:
          type: string
          description: AT synchronization status
          example: FAILED
        atCode:
          type: object
          description: AT code
          example: null
          nullable: true
        atMessage:
          type: string
          description: AT message
          example: AT sync failed without error details
        systemError:
          type: object
          description: System error
          example: null
          nullable: true
        isRetriable:
          type: boolean
          description: Can be retried
          example: false
        updatedAt:
          type: string
          description: Last update date
          example: '2025-10-28T11:58:01.936Z'
      required:
        - status
        - atCode
        - atMessage
        - systemError
        - isRetriable
        - updatedAt
    IssueInvoiceResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Unique invoice identifier
          example: 6900afc7e9a04d2adc897c68
        number:
          type: string
          description: Document number
          example: FT 2025/001
        atcud:
          type: string
          description: Unique document code (ATCUD)
          example: JFDSK3D4-1
        shortHash:
          type: string
          description: Document hash summary (4 characters) printed on the PDF
          example: AB3F
        documentType:
          type: string
          description: Document type
          example: INVOICE
        status:
          type: string
          description: Invoice status
          example: ISSUED
        notes:
          type: object
          description: Invoice notes
          example: null
          nullable: true
        series:
          description: Invoice series
          allOf:
            - $ref: '#/components/schemas/SeriesDto'
        payment:
          type: object
          description: Payment
          example: null
          nullable: true
        customer:
          description: Customer
          allOf:
            - $ref: '#/components/schemas/CustomerDto'
        dueDate:
          type: string
          description: Invoice due date
          example: '2025-11-04T07:00:00.000Z'
        date:
          type: string
          description: Invoice issue date
          example: '2025-10-28T11:57:59.008Z'
        taxPointDate:
          type: string
          description: >-
            Date of supply, when recorded (art. 36.º n.º 5 al. f) CIVA). Comes
            back null when it was not recorded — the issue date applies in that
            case.
          example: '2025-10-20T07:00:00.000Z'
          format: date-time
          nullable: true
        items:
          description: Invoice items
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemResponseDto'
        syncWithAt:
          description: AT synchronization status
          allOf:
            - $ref: '#/components/schemas/SyncWithAtDto'
      required:
        - id
        - number
        - atcud
        - shortHash
        - documentType
        - status
        - notes
        - series
        - payment
        - customer
        - dueDate
        - date
        - taxPointDate
        - items
        - syncWithAt
    PayInvoiceDto:
      type: object
      properties:
        method:
          type: string
          description: Payment method
          enum:
            - cash
            - card
            - bankTransfer
            - mbWay
            - multibanco
            - spin
            - other
          example: mbWay
        date:
          type: string
          description: Payment date
          example: '2025-11-04T07:00:00.000Z'
        amount:
          type: number
          description: >-
            Amount paid (optional). When omitted, the full outstanding balance
            is settled. Minimum 0.01, at most two decimal places.
          minimum: 0.01
          multipleOf: 0.01
          example: 123.45
      required:
        - method
        - date
    LegacyPaymentDto:
      type: object
      properties:
        method:
          type: string
          description: Payment method
          example: bankTransfer
        date:
          type: string
          description: Payment date
          example: '2025-11-04T07:00:00.000Z'
      required:
        - method
        - date
    PaymentDto:
      type: object
      properties:
        method:
          type: string
          description: Payment method
          example: bankTransfer
        date:
          type: string
          description: Payment date
          example: '2025-11-04T07:00:00.000Z'
        amount:
          type: number
          description: Amount paid
          example: 123.45
      required:
        - method
        - date
        - amount
    PayInvoiceReceiptDto:
      type: object
      properties:
        id:
          type: string
          description: Unique receipt identifier — use it in GET /invoices/{id}/pdf
          example: 6900afc7e9a04d2adc897c99
        number:
          type: string
          description: Receipt number
          example: RG 2025/001
          nullable: true
        atcud:
          type: string
          description: Unique document code (ATCUD)
          example: JFDSK3D4-1
          nullable: true
        documentType:
          type: string
          description: Document type
          example: RECEIPT
        status:
          type: string
          description: Receipt status
          example: ISSUED
        date:
          type: string
          description: Receipt issue date
          example: '2025-11-04T07:00:00.000Z'
        series:
          description: Receipt series
          allOf:
            - $ref: '#/components/schemas/SeriesDto'
      required:
        - id
        - number
        - atcud
        - documentType
        - status
        - date
        - series
    PayInvoiceItemMetaDto:
      type: object
      properties:
        quantity:
          type: number
          description: Quantity
          example: 1
        taxAmount:
          type: number
          description: Tax amount
          example: 23
      required:
        - quantity
        - taxAmount
    PayInvoiceItemDto:
      type: object
      properties:
        id:
          type: string
          description: Identifier of the item on the invoice
          example: 6900afc77a570c16377ee6da
        ref:
          type: string
          description: Item reference
          example: 68483e978073231c3947077c
        meta:
          description: Item metadata
          allOf:
            - $ref: '#/components/schemas/PayInvoiceItemMetaDto'
        data:
          description: Item data
          allOf:
            - $ref: '#/components/schemas/ItemDataDto'
      required:
        - id
        - ref
        - meta
        - data
    PayInvoiceResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Unique invoice identifier
          example: 6900afc7e9a04d2adc897c68
        number:
          type: string
          description: Invoice number
          example: FT 2025/001
        documentType:
          type: string
          description: Document type
          example: INVOICE
        status:
          type: string
          description: Invoice status
          example: PAID
        notes:
          type: string
          description: Invoice notes
          example: null
          nullable: true
        series:
          description: Invoice series
          allOf:
            - $ref: '#/components/schemas/SeriesDto'
        payment:
          description: >-
            Legacy field, populated only once the invoice is fully paid. On a
            partial payment it is null — use `payments`.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/LegacyPaymentDto'
        payments:
          description: Every payment registered against the invoice, including each amount.
          type: array
          items:
            $ref: '#/components/schemas/PaymentDto'
        receipt:
          description: >-
            Receipt (RG) issued by this payment, carrying the id needed to
            download its PDF from GET /invoices/{id}/pdf. On a partial payment
            this is the receipt for this payment, not an earlier one. Null for
            AT-imported invoices, for which no receipt is issued.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/PayInvoiceReceiptDto'
        customer:
          description: Customer
          allOf:
            - $ref: '#/components/schemas/CustomerDto'
        dueDate:
          type: string
          description: Invoice due date
          example: '2025-11-04T07:00:00.000Z'
        date:
          type: string
          description: Invoice issue date
          example: '2025-10-28T11:57:59.008Z'
        taxPointDate:
          type: string
          description: >-
            Date of supply, when recorded (art. 36.º n.º 5 al. f) CIVA). Comes
            back null when it was not recorded — the issue date applies in that
            case.
          example: '2025-10-20T07:00:00.000Z'
          format: date-time
          nullable: true
        items:
          description: Invoice items
          type: array
          items:
            $ref: '#/components/schemas/PayInvoiceItemDto'
        syncWithAt:
          description: AT synchronization status
          allOf:
            - $ref: '#/components/schemas/SyncWithAtDto'
      required:
        - id
        - number
        - documentType
        - status
        - notes
        - series
        - payment
        - payments
        - receipt
        - customer
        - dueDate
        - date
        - taxPointDate
        - items
        - syncWithAt
    CancelInvoiceResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Unique invoice identifier
          example: 6900afc7e9a04d2adc897c68
        number:
          type: string
          description: Document number
          example: FR FIZ2026/336
        documentType:
          type: string
          description: Document type
          example: INVOICE_RECEIPT
        status:
          type: string
          description: Invoice status
          example: CANCELED
        canceledAt:
          type: object
          description: Cancellation date
          example: '2026-06-30T10:00:00.000Z'
          nullable: true
        syncWithAt:
          description: AT synchronization status
          nullable: true
          allOf:
            - $ref: '#/components/schemas/SyncWithAtDto'
      required:
        - id
        - number
        - documentType
        - status
        - canceledAt
        - syncWithAt
    DownloadInvoicePdfResponseDto:
      type: object
      properties:
        id:
          type: string
          description: PDF file ID
          example: 68483b3fa19e44171e3d0808
        name:
          type: string
          description: PDF file name
          example: invoice-2024-001.pdf
          nullable: true
        url:
          type: string
          description: PDF download URL
          example: https://example.com/invoices/invoice-2024-001.pdf
          nullable: true
      required:
        - id
        - name
        - url
    TransportAddressDto:
      type: object
      properties:
        name:
          type: string
          description: Location name (e.g. warehouse, store, facility)
          example: Armazém Lisboa
        addressDetail:
          type: string
          description: Address (street, number, floor)
          example: Rua da Prata, 12, 2.º
        postalCode:
          type: string
          description: Postal code
          example: 1100-052
        city:
          type: string
          description: Locality
          example: Lisboa
        country:
          type: string
          description: Country (ISO 3166-1 alpha-2 code)
          example: PT
        ref:
          type: string
          description: >-
            Identifier of a saved address (optional). Links this address to an
            address book record.
          example: 68483b3fa19e44171e3d0808
      required:
        - name
        - addressDetail
        - postalCode
        - city
        - country
    TransportDocumentCustomerDataDto:
      type: object
      properties:
        name:
          type: string
          description: Recipient name
          example: Padaria Central, Lda
        taxpayerNumber:
          type: string
          description: Recipient NIF (tax number)
          example: '501234560'
        address:
          type: string
          description: Recipient address
          example: Av. da Liberdade, 200
        postalCode:
          type: string
          description: Recipient postal code
          example: 1250-147
        city:
          type: string
          description: Recipient locality
          example: Lisboa
        country:
          type: string
          description: Recipient country (ISO 3166-1 alpha-2)
          example: PT
      required:
        - name
    TransportDocumentCustomerDto:
      type: object
      properties:
        data:
          description: Recipient data
          allOf:
            - $ref: '#/components/schemas/TransportDocumentCustomerDataDto'
        ref:
          type: string
          description: >-
            Identifier of an existing customer (optional). Use the "id" returned
            by GET /customers.
          example: 6863b1513117c5892ff55296
      required:
        - data
    TransportDocumentItemDto:
      type: object
      properties:
        id:
          type: string
          description: Item identifier. Use the "id" returned by GET /items.
          example: 68483e978073231c3947077c
        quantity:
          type: number
          description: Transported quantity
          example: 10
          minimum: 1
      required:
        - id
        - quantity
    CreateTransportDocumentDto:
      type: object
      properties:
        movementType:
          type: string
          description: >-
            Movement type. GUIA_DE_REMESSA (delivery to a customer),
            GUIA_DE_DEVOLUCAO (return), GUIA_DE_TRANSPORTE (generic transport),
            GUIA_DE_ATIVOS_PROPRIOS (transfer between own facilities),
            GUIA_DE_CONSIGNACAO (consignment).
          enum:
            - GUIA_DE_ATIVOS_PROPRIOS
            - GUIA_DE_CONSIGNACAO
            - GUIA_DE_DEVOLUCAO
            - GUIA_DE_REMESSA
            - GUIA_DE_TRANSPORTE
          example: GUIA_DE_REMESSA
        movementDate:
          type: string
          description: >-
            Movement date (ISO 8601 with timezone). Cannot be earlier than today
            — the transport document must be reported to the AT before the
            transport starts.
          example: '2026-07-22T08:00:00.000Z'
        movementStartTime:
          type: string
          description: Loading date/time (ISO 8601 with timezone)
          example: '2026-07-22T08:30:00.000Z'
        movementEndTime:
          type: string
          description: Expected unloading date/time (optional, ISO 8601 with timezone)
          example: '2026-07-22T14:00:00.000Z'
        addressFrom:
          description: Loading location
          allOf:
            - $ref: '#/components/schemas/TransportAddressDto'
        addressTo:
          description: Unloading location (optional)
          allOf:
            - $ref: '#/components/schemas/TransportAddressDto'
        customer:
          description: >-
            Recipient of the goods. Required for all movement types except
            GUIA_DE_ATIVOS_PROPRIOS (movement of own assets). Only Portuguese
            recipients (country = "PT") are accepted — transport documents are
            reported to the Portuguese AT.
          allOf:
            - $ref: '#/components/schemas/TransportDocumentCustomerDto'
        vehicleID:
          type: string
          description: Vehicle license plate (optional)
          example: AA-00-BB
        items:
          description: Transported goods and their quantities
          example:
            - id: 68483e978073231c3947077c
              quantity: 10
          type: array
          items:
            $ref: '#/components/schemas/TransportDocumentItemDto'
      required:
        - movementType
        - movementDate
        - movementStartTime
        - addressFrom
        - items
    UpdateTransportDocumentDto:
      type: object
      properties:
        movementType:
          type: string
          description: Movement type
          enum:
            - GUIA_DE_ATIVOS_PROPRIOS
            - GUIA_DE_CONSIGNACAO
            - GUIA_DE_DEVOLUCAO
            - GUIA_DE_REMESSA
            - GUIA_DE_TRANSPORTE
          example: GUIA_DE_REMESSA
        movementDate:
          type: string
          description: >-
            Movement date (ISO 8601 with timezone). Cannot be earlier than
            today.
          example: '2026-07-22T08:00:00.000Z'
        movementStartTime:
          type: string
          description: Loading date/time (ISO 8601 with timezone)
          example: '2026-07-22T08:30:00.000Z'
        movementEndTime:
          type: string
          description: Expected unloading date/time (ISO 8601 with timezone)
          example: '2026-07-22T14:00:00.000Z'
        addressFrom:
          description: Loading location
          allOf:
            - $ref: '#/components/schemas/TransportAddressDto'
        addressTo:
          description: Unloading location
          allOf:
            - $ref: '#/components/schemas/TransportAddressDto'
        customer:
          description: Recipient of the goods
          allOf:
            - $ref: '#/components/schemas/TransportDocumentCustomerDto'
        vehicleID:
          type: string
          description: Vehicle license plate
          example: AA-00-BB
        items:
          description: Transported goods and their quantities
          example:
            - id: 68483e978073231c3947077c
              quantity: 10
          type: array
          items:
            $ref: '#/components/schemas/TransportDocumentItemDto'
    DownloadTransportDocumentPdfResponseDto:
      type: object
      properties:
        id:
          type: string
          description: PDF file ID
          example: 68483b3fa19e44171e3d0808
        name:
          type: string
          description: PDF file name
          example: GT-2026-001.pdf
          nullable: true
        url:
          type: string
          description: PDF download URL
          example: https://example.com/transport-documents/GT-2026-001.pdf
          nullable: true
      required:
        - id
        - name
        - url
    CreateProposalDto:
      type: object
      properties:
        date:
          type: string
          description: >-
            Document date (optional). If omitted, the current date and time are
            used.
          example: '2025-10-15T07:00:00.000Z'
        dueDate:
          type: string
          description: >-
            Validity / due date of the pro forma (optional). If omitted, the
            document date is used.
          example: '2025-11-04T07:00:00.000Z'
        cae:
          type: string
          description: >-
            CAE code (economic activity classification). Optional on a pro
            forma, but required once it is converted into an invoice.
          example: '1234'
        customerId:
          type: string
          description: Customer identifier
          example: 6863b1513117c5892ff55296
        seriesId:
          type: string
          description: Series identifier (optional). Use the "id" returned by GET /series.
          example: 68483b3fa19e44171e3d0808
        notes:
          type: string
          description: Pro forma notes (optional)
          example: Proposta válida por 30 dias
        items:
          description: List of pro forma items
          example:
            - id: 68483e978073231c3947077c
              quantity: 1
              discountType: PERCENT
              discountPercent: 10
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemDto'
        summary:
          description: Pro forma summary with global discount (optional)
          example:
            globalDiscountType: PERCENT
            globalDiscountPercent: 10
          allOf:
            - $ref: '#/components/schemas/InvoiceSummaryInputDto'
      required:
        - customerId
        - items
    RelatedDocumentDto:
      type: object
      properties:
        id:
          type: string
          description: Identifier of the invoice raised from the pro forma
          example: 6900afc7e9a04d2adc897c68
        number:
          type: string
          description: Invoice number
          example: FT FIZ2026/12
          nullable: true
        documentType:
          type: string
          description: Document type
          example: INVOICE
        status:
          type: string
          description: Invoice status
          example: ISSUED
        date:
          type: string
          description: Invoice date
          example: '2025-10-28T11:57:59.008Z'
      required:
        - id
        - number
        - documentType
        - status
        - date
    ProposalResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Unique pro forma identifier
          example: 6900afc7e9a04d2adc897c68
        number:
          type: string
          description: Pro forma number, assigned at creation
          example: PF FIZ2026/1
          nullable: true
        documentType:
          type: string
          description: Document type
          enum:
            - PROFORMA
          example: PROFORMA
        status:
          type: string
          description: >-
            Status: CREATED (active), ISSUED (converted into an invoice),
            CANCELED (void)
          enum:
            - CANCELED
            - CREATED
            - ISSUED
            - PROCESSING
          example: CREATED
        date:
          type: string
          description: Document date
          example: '2025-10-28T11:57:59.008Z'
        dueDate:
          type: string
          description: Validity / due date
          example: '2025-11-04T07:00:00.000Z'
        currency:
          type: string
          description: Currency
          example: EUR
        notes:
          type: string
          description: Notes
          example: Proposta válida por 30 dias
          nullable: true
        cae:
          type: string
          description: CAE code
          example: '1234'
          nullable: true
        series:
          description: Series
          nullable: true
          allOf:
            - $ref: '#/components/schemas/SeriesDto'
        customer:
          description: Customer
          allOf:
            - $ref: '#/components/schemas/CustomerDto'
        summary:
          description: Totals
          allOf:
            - $ref: '#/components/schemas/InvoiceSummaryDto'
        items:
          description: Items
          type: array
          items:
            $ref: '#/components/schemas/InvoiceItemResponseDto'
        relatedDocuments:
          description: Invoices raised from this pro forma
          type: array
          items:
            $ref: '#/components/schemas/RelatedDocumentDto'
        createdAt:
          type: string
          description: Creation date
          example: '2025-10-28T11:57:59.008Z'
        canceledAt:
          type: string
          description: Cancellation date, when canceled
          example: '2025-11-02T09:00:00.000Z'
          nullable: true
      required:
        - id
        - number
        - documentType
        - status
        - date
        - dueDate
        - currency
        - notes
        - cae
        - series
        - customer
        - summary
        - items
        - relatedDocuments
        - createdAt
        - canceledAt
    DeleteProposalResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Identifier of the deleted pro forma
          example: 6900afc7e9a04d2adc897c68
        number:
          type: string
          description: Number of the deleted pro forma
          example: PF FIZ2026/1
          nullable: true
        status:
          type: string
          description: Status at the time of deletion
          enum:
            - CANCELED
            - CREATED
            - ISSUED
            - PROCESSING
          example: CREATED
      required:
        - id
        - number
        - status
    DownloadProposalPdfResponseDto:
      type: object
      properties:
        id:
          type: string
          description: PDF file ID
          example: 68483b3fa19e44171e3d0808
        name:
          type: string
          description: PDF file name
          example: PF-FIZ2026-1.pdf
          nullable: true
        url:
          type: string
          description: PDF download URL
          example: https://example.com/proposals/PF-FIZ2026-1.pdf
          nullable: true
      required:
        - id
        - name
        - url
    CreateCustomerDto:
      type: object
      properties:
        name:
          type: string
          description: Customer name
          example: João Silva
        firstName:
          type: string
          description: First name
          example: João
        lastName:
          type: string
          description: Last name
          example: Silva
        email:
          type: string
          description: Customer email
          example: joao.silva@example.com
        taxpayerNumber:
          type: string
          description: Tax number (NIF)
          example: '303741791'
        country:
          type: string
          description: Country code (ISO 3166-1 alpha-2)
          example: PT
          default: PT
        phone:
          type: string
          description: Phone
          example: '+351912345678'
        mobile:
          type: string
          description: Mobile phone
          example: '+351912345678'
        fax:
          type: string
          description: Fax
          example: '+351212345678'
        address:
          type: string
          description: Address
          example: Rua das Flores, 123
        city:
          type: string
          description: City
          example: Lisboa
        postalCode:
          type: string
          description: Postal code
          example: 1000-100
        website:
          type: string
          description: Website
          example: https://example.com
        companyName:
          type: string
          description: Company name
          example: Silva & Associados Lda
        companyPosition:
          type: string
          description: Position in the company
          example: Diretor Geral
        description:
          type: string
          description: Description
          example: Cliente VIP
        photo:
          type: string
          description: Photo URL
          example: https://example.com/photo.jpg
      required:
        - name
    CreateCustomerResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Unique customer identifier
          example: 6863b1513117c5892ff55296
        taxpayerNumber:
          type: string
          description: Tax number (NIF)
          example: '303741791'
          nullable: true
        name:
          type: string
          description: Customer name
          example: João Silva
          nullable: true
        photo:
          type: string
          description: Photo URL
          example: https://example.com/photo.jpg
          nullable: true
        companyName:
          type: string
          description: Company name
          example: Silva & Associados Lda
          nullable: true
        companyPosition:
          type: string
          description: Position in the company
          example: Diretor Geral
          nullable: true
        email:
          type: string
          description: Customer email
          example: joao.silva@example.com
          nullable: true
        website:
          type: string
          description: Website
          example: https://example.com
          nullable: true
        description:
          type: string
          description: Description
          example: Cliente VIP
          nullable: true
        address:
          type: string
          description: Address
          example: Rua das Flores, 123
          nullable: true
        postalCode:
          type: string
          description: Postal code
          example: 1000-100
          nullable: true
        country:
          type: string
          description: Country code
          example: PT
          nullable: true
        phone:
          type: string
          description: Phone
          example: '+351912345678'
          nullable: true
        fax:
          type: string
          description: Fax
          example: '+351212345678'
          nullable: true
        mobile:
          type: string
          description: Mobile phone
          example: '+351912345678'
          nullable: true
        city:
          type: string
          description: City
          example: Lisboa
          nullable: true
      required:
        - id
        - taxpayerNumber
        - name
        - photo
        - companyName
        - companyPosition
        - email
        - website
        - description
        - address
        - postalCode
        - country
        - phone
        - fax
        - mobile
        - city
    UpdateCustomerDto:
      type: object
      properties:
        name:
          type: string
          description: Customer name
          example: João Silva
        firstName:
          type: string
          description: First name
          example: João
        lastName:
          type: string
          description: Last name
          example: Silva
        email:
          type: string
          description: Customer email
          example: joao.silva@example.com
        taxpayerNumber:
          type: string
          description: Tax number (NIF)
          example: '303741791'
        country:
          type: string
          description: Country code (ISO 3166-1 alpha-2)
          example: PT
          default: PT
        phone:
          type: string
          description: Phone
          example: '+351912345678'
        mobile:
          type: string
          description: Mobile phone
          example: '+351912345678'
        fax:
          type: string
          description: Fax
          example: '+351212345678'
        address:
          type: string
          description: Address
          example: Rua das Flores, 123
        city:
          type: string
          description: City
          example: Lisboa
        postalCode:
          type: string
          description: Postal code
          example: 1000-100
        website:
          type: string
          description: Website
          example: https://example.com
        companyName:
          type: string
          description: Company name
          example: Silva & Associados Lda
        companyPosition:
          type: string
          description: Position in the company
          example: Diretor Geral
        description:
          type: string
          description: Description
          example: Cliente VIP
        photo:
          type: string
          description: Photo URL
          example: https://example.com/photo.jpg
    CreateItemDto:
      type: object
      properties:
        name:
          type: string
          description: Item name
          example: TV LG 55
        description:
          type: string
          description: Item description
          example: Televisão LG 55 polegadas 4K
        type:
          type: string
          description: Item type
          enum:
            - PRODUCT
            - SERVICE
          example: PRODUCT
        unitPrice:
          type: number
          description: Unit price
          example: 1500
        unitType:
          type: string
          description: Unit type
          enum:
            - BOX
            - CUBIC_METER
            - DAY
            - HOUR
            - KILOGRAM
            - LITER
            - METER
            - MONTH
            - NA
            - PACKAGE
            - SQUARE_METER
            - UNIT
            - WEEK
          example: UNIT
        unitDiscountType:
          type: string
          description: >-
            Default discount type for the catalogue item (optional). Without
            this field no discount is applied, even if unitDiscountPercent or
            unitDiscountAmount is set.
          enum:
            - AMOUNT
            - PERCENT
          example: PERCENT
        unitDiscountPercent:
          type: number
          description: >-
            Default discount percentage for the catalogue item (e.g. 10 for
            10%). Requires unitDiscountType=PERCENT.
          example: 10
          minimum: 0
          maximum: 100
        unitDiscountAmount:
          type: number
          description: >-
            Default absolute per-unit discount amount for the catalogue item.
            Requires unitDiscountType=AMOUNT and must not exceed unitPrice.
          example: 25
          minimum: 0
        vatRate:
          type: string
          description: VAT rate
          enum:
            - EXEMPT
            - INTERMEDIATE
            - NORMAL
            - REDUCED
          example: NORMAL
        vatTerritory:
          type: string
          description: VAT territory
          enum:
            - CONTINENTAL
            - MADEIRA
            - AZORES
          example: CONTINENTAL
        ossCountry:
          type: string
          description: OSS country (mutually exclusive with vatTerritory)
          example: ES
        taxRate:
          type: number
          description: Tax rate (percentage)
          example: 23
        vatExemptionReason:
          type: string
          description: VAT exemption reason
          example: M01
        termsOfPayment:
          type: string
          description: Payment terms
          example: Pagamento a 30 dias
        isAutoVATEnabled:
          type: boolean
          description: Automatic VAT enabled
          example: false
        withholdingTaxAvailable:
          type: boolean
          description: Withholding tax available
          example: false
        withholdingTaxPercent:
          type: number
          description: Withholding tax percentage
          example: 25
        withholdingTaxType:
          type: string
          description: Withholding tax type
          enum:
            - IRC
            - IRS
            - IS
          example: IRS
        withholdingTaxReason:
          type: string
          description: Withholding tax reason
          example: Serviços profissionais
      required:
        - name
        - type
        - unitPrice
        - vatRate
    CreateItemResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Unique item identifier
          example: 68483e978073231c3947077c
        name:
          type: string
          description: Item name
          example: TV LG 55
          nullable: true
        description:
          type: string
          description: Item description
          example: Televisão LG 55 polegadas 4K
          nullable: true
        type:
          type: string
          description: Item type
          enum:
            - PRODUCT
            - SERVICE
          example: PRODUCT
        termsOfPayment:
          type: string
          description: Payment terms
          example: Pagamento a 30 dias
          nullable: true
        unitPrice:
          type: number
          description: Unit price
          example: 1500
          nullable: true
        unitType:
          type: string
          description: Unit type
          enum:
            - BOX
            - CUBIC_METER
            - DAY
            - HOUR
            - KILOGRAM
            - LITER
            - METER
            - MONTH
            - NA
            - PACKAGE
            - SQUARE_METER
            - UNIT
            - WEEK
          example: UNIT
          nullable: true
        unitDiscountType:
          type: string
          description: Default discount type for the catalogue item
          enum:
            - AMOUNT
            - PERCENT
          example: PERCENT
          nullable: true
        unitDiscountPercent:
          type: number
          description: Default discount percentage for the catalogue item
          example: 10
          nullable: true
        unitDiscountAmount:
          type: number
          description: Default absolute per-unit discount amount for the catalogue item
          example: 25
          nullable: true
        vatRate:
          type: string
          description: VAT rate
          enum:
            - EXEMPT
            - INTERMEDIATE
            - NORMAL
            - REDUCED
          example: NORMAL
          nullable: true
        vatTerritory:
          type: string
          description: VAT territory
          enum:
            - AZORES
            - CONTINENTAL
            - MADEIRA
            - UNKNOWN
          example: CONTINENTAL
          nullable: true
        ossCountry:
          type: string
          description: OSS country
          example: ES
          nullable: true
        taxRate:
          type: number
          description: Tax rate
          example: 23
          nullable: true
        vatExemptionReason:
          type: string
          description: VAT exemption reason
          example: M01
          nullable: true
        withholdingTaxPercent:
          type: number
          description: Withholding tax percentage
          example: 25
          nullable: true
        withholdingTaxType:
          type: string
          description: Withholding tax type
          enum:
            - IRC
            - IRS
            - IS
          example: IRS
          nullable: true
        withholdingTaxAvailable:
          type: boolean
          description: Withholding tax available
          example: false
          nullable: true
        withholdingTaxReason:
          type: string
          description: Withholding tax reason
          example: Serviços profissionais
          nullable: true
        autoVATModeAvailable:
          type: boolean
          description: Automatic VAT mode available
          example: true
          nullable: true
        isAutoVATEnabled:
          type: boolean
          description: Automatic VAT enabled
          example: false
          nullable: true
      required:
        - id
        - name
        - description
        - type
        - termsOfPayment
        - unitPrice
        - unitType
        - unitDiscountType
        - unitDiscountPercent
        - unitDiscountAmount
        - vatRate
        - vatTerritory
        - ossCountry
        - taxRate
        - vatExemptionReason
        - withholdingTaxPercent
        - withholdingTaxType
        - withholdingTaxAvailable
        - withholdingTaxReason
        - autoVATModeAvailable
        - isAutoVATEnabled
    UpdateItemDto:
      type: object
      properties:
        name:
          type: string
          description: Item name
          example: TV LG 55
        description:
          type: string
          description: Item description
          example: Televisão LG 55 polegadas 4K
        unitPrice:
          type: number
          description: Unit price
          example: 1500
        unitType:
          type: string
          description: Unit type
          enum:
            - BOX
            - CUBIC_METER
            - DAY
            - HOUR
            - KILOGRAM
            - LITER
            - METER
            - MONTH
            - NA
            - PACKAGE
            - SQUARE_METER
            - UNIT
            - WEEK
          example: UNIT
        vatRate:
          type: string
          description: VAT rate
          enum:
            - EXEMPT
            - INTERMEDIATE
            - NORMAL
            - REDUCED
          example: NORMAL
        vatTerritory:
          type: string
          description: VAT territory
          enum:
            - CONTINENTAL
            - MADEIRA
            - AZORES
          example: CONTINENTAL
        ossCountry:
          type: string
          description: OSS country (mutually exclusive with vatTerritory)
          example: ES
        taxRate:
          type: number
          description: Tax rate (percentage)
          example: 23
        vatExemptionReason:
          type: string
          description: VAT exemption reason
          example: M01
        termsOfPayment:
          type: string
          description: Payment terms
          example: Pagamento a 30 dias
        isAutoVATEnabled:
          type: boolean
          description: Automatic VAT enabled
          example: false
        withholdingTaxAvailable:
          type: boolean
          description: Withholding tax available
          example: false
        withholdingTaxPercent:
          type: number
          description: Withholding tax percentage
          example: 25
        withholdingTaxType:
          type: string
          description: Withholding tax type
          enum:
            - IRC
            - IRS
            - IS
          example: IRS
        withholdingTaxReason:
          type: string
          description: Withholding tax reason
          example: Serviços profissionais
        type:
          type: string
          description: Item type
          enum:
            - PRODUCT
            - SERVICE
          example: PRODUCT
        unitDiscountType:
          type: string
          description: >-
            Discount type for the catalogue item. Send null to remove the
            discount. If omitted, the type already stored on the item is kept.
          enum:
            - AMOUNT
            - PERCENT
          example: PERCENT
          nullable: true
        unitDiscountPercent:
          type: number
          description: >-
            Discount percentage for the catalogue item (e.g. 10 for 10%).
            Requires unitDiscountType=PERCENT, either in the request or already
            stored on the item.
          example: 10
          minimum: 0
          maximum: 100
        unitDiscountAmount:
          type: number
          description: >-
            Absolute per-unit discount amount for the catalogue item. Requires
            unitDiscountType=AMOUNT, either in the request or already stored on
            the item, and must not exceed unitPrice.
          example: 25
          minimum: 0
      required:
        - type
    GetTemplatesResponseDto:
      type: object
      properties:
        id:
          type: string
          description: Unique template identifier
          example: 68483b3fa19e44171e3d0808
        name:
          type: string
          description: Template name
          example: Modelo Padrão
        cae:
          description: List of CAE codes (Portuguese classification of economic activities)
          example:
            - '1234'
            - '5678'
          type: array
          items:
            type: string
      required:
        - id
        - name
    SerieEntryResponseDto:
      type: object
      properties:
        documentType:
          type: string
          description: Document type the series entry applies to
          example: INVOICE
        validationCode:
          type: object
          description: Series validation code (ATCUD) assigned by the AT
          example: AAJF
          nullable: true
        isVerified:
          type: object
          description: Whether the entry is verified/reported to the AT
          example: true
          nullable: true
      required:
        - documentType
    GetSeriesResponseDto:
      type: object
      properties:
        id:
          type: string
          description: >-
            Unique series identifier (use it as seriesId when creating an
            invoice)
          example: 68483b3fa19e44171e3d0808
        name:
          type: object
          description: Series name
          example: SAAS
          nullable: true
        isDefault:
          type: object
          description: Whether this is the account's default series
          example: true
          nullable: true
        status:
          type: object
          description: Series status
          example: ACTIVE
          nullable: true
        managementMode:
          type: object
          description: Numbering management mode (AUTOMATIC or MANUAL)
          example: AUTOMATIC
          nullable: true
        entries:
          description: Series entries per document type (with ATCUD)
          nullable: true
          type: array
          items:
            $ref: '#/components/schemas/SerieEntryResponseDto'
      required:
        - id
    CalculateVatDto:
      type: object
      properties:
        clientHasVat:
          type: boolean
          description: >-
            Whether the customer has a VAT number (B2B). Use false for final
            consumers (B2C)
          example: false
        clientCountry:
          type: string
          description: Customer country code (ISO 3166-1 alpha-2)
          example: PT
          default: PT
        clientTerritory:
          type: string
          description: Customer territory, Portugal only
          enum:
            - continental
            - azores
            - madeira
          example: continental
        clientVatNumber:
          type: string
          description: >-
            Customer VAT number. For PT customers use the national NIF, without
            the country prefix (a "PT" prefix is removed automatically); for
            other EU countries it is validated via VIES
          example: '503244732'
        clientPostalCode:
          type: string
          description: Customer postal code
          example: 1000-100
        clientIsTIENI:
          type: boolean
          description: >-
            Whether the individual customer is a sole trader (TI/ENI —
            Trabalhador Independente or Empresário em Nome Individual). Used to
            resolve the territory of Portuguese B2B customers with an
            individual's NIF
          example: false
        itemType:
          type: string
          description: Item type
          enum:
            - PRODUCT
            - SERVICE
          example: SERVICE
        itemText:
          type: string
          description: Item description
          example: Serviço de consultoria
        invoiceCae:
          type: string
          description: Invoice CAE (economic activity code)
          example: '62010'
      required:
        - clientHasVat
        - itemType
    VatInfoDto:
      type: object
      properties:
        rate:
          type: number
          description: >-
            Applicable VAT rate (percentage). It is always the standard rate of
            the determined regime/territory (e.g. 23% mainland PT, 16% Azores,
            the customer country's standard rate under OSS) or 0 in case of
            exemption. Reduced and intermediate rates are not determined — if
            the item qualifies for a reduced rate, it is up to the integrator to
            select it when creating the invoice
          example: 23
        reason:
          type: object
          description: >-
            Exemption reason code (e.g. 40 = reverse charge, 16 = Art. 16), null
            when VAT applies
          example: null
          nullable: true
        text:
          type: string
          description: Explanatory text for the applied rate/exemption
          example: 'VAT normal rate by merchant territory in PT: continental'
      required:
        - rate
        - reason
        - text
    VatClientDto:
      type: object
      properties:
        country:
          type: string
          description: Customer country used in the calculation (normalized)
          example: PT
        territory:
          type: object
          description: >-
            Customer territory used in the calculation. For Portuguese B2B
            customers it can be resolved automatically from the postal code
          example: continental
          nullable: true
        vies:
          type: object
          description: >-
            Validated-VAT-number indicator used in the calculation (0 or 1).
            Explains why an EU B2B sale did (or did not) get reverse charge /
            intra-community exemption. Mind the semantics: for EU countries
            (except PT) it reflects VIES validation; for PT and non-EU customers
            only the presence of a number; if the VIES service is unavailable,
            the clientHasVat value provided in the request is used
          example: 0
          nullable: true
      required:
        - country
    CalculateVatResponseDto:
      type: object
      properties:
        vat:
          description: VAT calculation result
          allOf:
            - $ref: '#/components/schemas/VatInfoDto'
        client:
          description: Customer data used in the calculation
          allOf:
            - $ref: '#/components/schemas/VatClientDto'
        warning:
          type: object
          description: Warning about the calculation (if applicable)
          example: null
          nullable: true
        warningCode:
          type: object
          description: Warning code (if applicable)
          example: null
          nullable: true
      required:
        - vat
        - client
    ValidateClientVatDto:
      type: object
      properties:
        clientHasVat:
          type: boolean
          description: >-
            Whether the customer has a VAT number (B2B). Use false for final
            consumers (B2C)
          example: true
        clientCountry:
          type: string
          description: Customer country code (ISO 3166-1 alpha-2)
          example: PT
        clientVatNumber:
          type: string
          description: >-
            Customer VAT number to validate. For PT customers use the national
            NIF, without the country prefix (a "PT" prefix is removed
            automatically)
          example: '503244732'
      required:
        - clientHasVat
    ValidateClientVatResponseDto:
      type: object
      properties:
        valid:
          type: boolean
          description: >-
            Verification result. Mind the semantics: for EU countries (except
            PT) the number is validated via VIES; for PT and non-EU customers
            only the presence of a number is checked (any non-empty value
            returns true). If the VIES service is unavailable, the clientHasVat
            value provided in the request is returned
          example: true
      required:
        - valid
    ReadinessReasonDto:
      type: object
      properties:
        code:
          type: string
          enum:
            - AT_CREDENTIALS_REQUIRED
            - AT_SYNC_REQUIRED
            - SERIES_REQUIRED
        actionUrl:
          type: string
          format: uri
      required:
        - code
        - actionUrl
    ReadinessDto:
      type: object
      properties:
        ready:
          type: boolean
        checkedAt:
          type: string
          format: date-time
        reasons:
          type: array
          items:
            $ref: '#/components/schemas/ReadinessReasonDto'
      required:
        - ready
        - checkedAt
        - reasons
    CompanyResponseDto:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        taxpayerNumber:
          type: string
          nullable: true
        cae:
          type: array
          items:
            type: string
        readiness:
          $ref: '#/components/schemas/ReadinessDto'
      required:
        - id
        - name
        - cae
        - readiness
info:
  title: FIZ Public API
  description: >-
    FIZ's public REST API for issuing and managing invoices, customers, and
    items.


    ## Authentication

    API-key access requires an API key in the `x-api-key` header.

    Each key belongs to one account/NIF and issues only for that account. Create
    your key at

    [app.fiz.co/settings/integrations](https://app.fiz.co/settings/integrations).


    Building an integration for customers? Follow the [partner app
    guide](/docs/apps) for a working example, OAuth, signup, permissions and
    retries.

    Registered apps can also use `Authorization: Bearer <access_token>` with
    resource `https://api.fiz.co`. Create an app at [Settings →
    Integrations](https://app.fiz.co/settings/integrations) and request explicit
    company consent. Never send a bearer and an API key together. A token for
    `/mcp` is not valid for REST.


    OAuth supports invoices, customers and items (`invoicing.read`,
    `invoicing.write`, `invoicing.issue`), plus `GET /company` and `GET /series`
    (`company.read`). Other routes require an API key. Registered apps read
    their own records; `invoicing.read_all` additionally permits company-wide
    reads, without permission to modify other records. Customer cards are
    separate for each app, even for the same tax number.


    Before issuing, check `GET /company` for readiness reasons and send the
    draft’s `updatedAt` as `expectedUpdatedAt` in the issue body. A changed
    draft is rejected. Readiness is a preliminary check, not a guarantee for a
    particular document. OAuth grants share a 300-request/minute budget across
    API replicas; a 429 carries `Retry-After`.


    ## Issuing flow

    Invoices are first created as a **draft** (`POST /invoices`) and are only
    reported to the

    Portuguese tax authority (AT) at the moment of **issuance** (`POST
    /invoices/{id}/issue`). You

    can validate all the data — and even generate the PDF — before issuing. Use
    drafts to test your

    integration without reporting to AT.


    ## Series and PDF templates

    - **Series** — list the account’s series at `GET /series` and pass the
    relevant `id` in the
      `seriesId` field when creating an invoice to issue it in a specific series. If omitted, the
      default series is used.
    - **PDF templates** — list templates at `GET /templates` and pass the
    relevant `id` in
      `GET /invoices/{id}/pdf?templateId=...` to generate the PDF with that template.

    ## Recurring invoices

    A schedule is an invoice template that FIZ issues — and reports to AT — on
    its own, at the

    frequency you set (`POST /invoices/scheduled`: `MONTHLY` on day 1, `WEEKLY`
    on Monday, …).

    Manage it from your system: `PATCH /invoices/scheduled/{id}` changes the
    frequency, dates or

    auto-send, or pauses and resumes it (`status`); `DELETE` ends it. Every
    document a schedule

    issues carries its id as `scheduleTemplateId`, so `GET
    /invoices?scheduleTemplateId=...`

    lists exactly what went out — that is how to reconcile. Requires a plan with
    recurring invoices.


    ## Idempotency

    Every endpoint that writes accepts an optional `Idempotency-Key` header (a
    UUID, say). Retrying a

    request with the same key returns the original response instead of executing
    it again — so a

    timeout or a dropped connection never costs you a duplicate invoice. Send a
    new key for a new

    request. Keys are scoped to your API key (or to the app, authorizing user
    and company for registered REST clients) and are remembered for 30 days.


    - A replayed response carries `Idempotent-Replayed: true` and repeats the
    original status code.

    - Reusing a key with a different request body is rejected with `422`.

    - `409` means the first attempt is still running (retry with the same key,
    honouring `Retry-After`)
      or that its outcome is unknown — check whether it took effect, then retry with a **new** key.

    A request we rejected before sending it on (a `400` from validation) leaves
    the key free to reuse.

    Any other failure — including one the invoicing backend reports — may
    already have taken effect, so

    the key is spent: check the result, then use a new key. Correcting a
    rejected payload is a new

    request, so give it a new key.


    Without the header nothing changes: requests behave exactly as they always
    have.


    ## Specification

    OpenAPI is available at [`/-json`](/-json) and [`/-yaml`](/-yaml), ideal for
    generating a REST

    client.


    ## For Claude and ChatGPT (MCP connector)

    FIZ is also an **MCP server**: connect it once and your assistant reads your
    documents, drafts

    invoices and — only after you confirm each one — issues them.


    Server URL: `https://api.fiz.co/mcp`


    - **Claude** (web, desktop, mobile) — Settings → Connectors → *Add custom
    connector*, paste the URL,
      then sign in to FIZ and choose the company and permissions.
    - **ChatGPT** — Settings → Apps & Connectors → *Create*, paste the URL, sign
    in to FIZ.

    - **Claude Code** — `claude mcp add --transport http fiz
    https://api.fiz.co/mcp`, then `/mcp` → Authenticate.


    No API key is involved: access is an OAuth connection you can revoke at any
    time in

    [app.fiz.co/settings/integrations](https://app.fiz.co/settings/integrations).
    Details, permissions

    and the list of tools: [api.fiz.co/docs/mcp](/docs/mcp).


    Prefer a coding agent with shell access? The open-source *skill*

    [FIZ-co/fiz-invoicing-skill](https://github.com/FIZ-co/fiz-invoicing-skill)
    (MIT) drives this REST API instead.
  version: '1.1'
  contact:
    name: Get an API key
    url: https://app.fiz.co/settings/integrations
    email: ''
