> ## Documentation Index
> Fetch the complete documentation index at: https://docs.str.keroshospitality.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Upload an STR task

> Create a new STR upload task for multiple reservations.

### Allowed Roles:
`admin`, `str-uploader`

### Special Validation Rules:
- Exactly one of: `amountReceived`, `cancellationAmount` must be provided.
- Exactly one of: `cancellationDate`, `endDate` must be provided.
- If `isForeigner` is true, then `guestName` and `guestId` are required.
- If `isForeigner` is false, then `guestTaxId` is required. `guestId` and `guestName` are ignored.
- `startDate` must be before `endDate`.



## OpenAPI

````yaml /openapi.json post /str/task
openapi: 3.0.3
info:
  title: STR Uploader API
  description: >
    The Taxis uploader API provides endpoints for uploading reservations to
    Government's Short Term Rental Registry and filing the Climate Crisis
    Resilience Fee Statement (TAKK).


    ## Overview


    This API allows you to:

    * Upload short-term rental records

    * Query sn str task's upload status

    * Uploading Climate Crisis Resilience Fee Statement

    * Query a TAKK statement's upload task status



    ## Authentication


    All API endpoints require JWT Bearer token authentication. The applicable
    roles for this API are: `str-uploader`, `takk-uploader`, `client-manager`.


    ### How to get a JWT token:

    1. Use your client ID and client secret obtained from your administrator

    2. Send a POST request to `/auth/token` with your credentials

    3. Use the returned `access_token` in the Authorization header: `Bearer
    <access_token>`


    ### Example with curl:

    ```bash

    curl -X POST {server}/api/v1/auth/token \

    -H "Content-Type: application/json" \

    -d '{

    "clientId": "your-client-id",

    "secret": "your-client-secret"

    }'

    ```


    ### Using the token:

    ```bash

    curl -X GET {server}/api/v1/clients \

    -H "Authorization: Bearer <your-access-token>"

    ```


    ### Token refresh:

    When your access token expires, use the refresh token:

    ```bash

    curl -X POST {server}/api/v1/auth/refresh \

    -H "Content-Type: application/json" \

    -d '{

    "refreshToken": "your-refresh-token-here"

    }'

    ```


    **Note:** Replace `{server}` with your actual server URL (e.g.,
    `https://api.yourdomain.com` or `http://localhost:8080` for local
    development).


    ## Response Formats


    All responses are in JSON format. Successful responses use HTTP 2xx status
    codes:

    * 200: Successful operation with response body

    * 201: Resource created

    * 202: Request accepted for processing

    * 204: Successful operation with no response body


    ## Error Responses


    Unsuccessful requests return a response with an error-indicating status
    code, and a json object with a 'errorMessage' and requestId field:

    ```json

    {

    "errorMessage": "Not found"

    "requestId": "a1b2c3d4-e5f6-7890-a1b2-c3d4e5f67890"

    }

    ```


    ## Apartment Owner Credentials Security Documentation


    ### Overview


    The Taxis Uploader service now implements a secure approach for managing
    Taxis user credentials (apartment owners).

    This document outlines our approach to securely storing, encrypting, and
    managing these credentials with security best practices.


    ### Credential Storage and Management

    Storage Model


    Taxis user credentials are stored in the database using the apartment_owners
    table

    Credentials are associated with a unique taxis_username

    Passwords are never stored in plain text in the database

    Clients reference Taxis users by username only, without needing to transmit
    passwords with each request


    ### Password Encryption


    All Taxis passwords are encrypted using AES-256-GCM symmetric encryption
    before storage

    Each password is encrypted with:


    A secure 256-bit encryption key stored separately from the database

    A unique random nonce (number used once) that is stored with the encrypted
    data


    The encryption process ensures:


    * The same password will encrypt to different ciphertext values each time

    * Patterns in the original data are obscured in the encrypted output

    * Decryption is only possible with access to both the encryption key and the
    ciphertext


    ### Security Mechanisms


    #### Key Management


    The 32-byte (256-bit) encryption key is stored in environment variables /
    KMS system, not in the codebase or database

    Different keys are used for each environment (development, staging,
    production)

    Access to the encryption key is strictly limited


    ### Nonce Handling


    A unique nonce is generated for each encryption operation

    The nonce is prepended to the ciphertext for decryption

    This prevents identical passwords from producing identical encrypted values


    ### API Security


    - Passwords are never returned in API responses

    - Response models explicitly omit password fields

    - HTTPS is enforced for all API communications

    - Proper authentication and authorization controls restrict access to
    credential management


    #### Benefits of This Approach


    Reduced Transmission Risk: Credentials are only transmitted when initially
    set up or updated, not with every reservation upload request

    Defense in Depth: Even if the database is compromised, the attacker would
    still need the encryption key to access passwords

    Improved User Experience: Clients don't need to store and transmit sensitive
    Taxis credentials with each request

    Better Auditability: Credential usage can be tracked and monitored centrally


    ### Technical Implementation Details


    Encryption: AES-256-GCM (Galois/Counter Mode)

    Key: 256-bit random key

    Nonce: 12 bytes of random data generated for each encryption operation


    ### Operational Considerations


    Passwords are only decrypted in memory when needed for Taxis operations

    Encryption keys are rotated periodically (recommended: every 90 days)

    During key rotation, all passwords are re-encrypted with the new key

    Monitoring should be in place to detect unusual access patterns to apartment
    owner records


    ### DefaultWebUser Developer Guidelines


    When using the Taxis Uploader service:


    - Store only the taxis_username in your application

    - Reference this username when submitting upload tasks

    - Do not attempt to retrieve or cache the password



    When creating or updating apartment owners:


    - Transmit credentials over HTTPS only

    - Don't log or store the plaintext password in your application

    = Confirm credentials are valid before storing them in our system


    ### Developer Contact
  version: 1.0.0
  contact:
    name: Mike Mylonakis
    email: contact@mikemylonakis.com
    url: https://mikemylonakis.com
servers:
  - url: https://str.keroshospitality.com/api/v1
    description: Production server
  - url: '{protocol}://{host}:{port}/api/v1'
    description: Configurable server
    variables:
      protocol:
        enum:
          - http
          - https
        default: http
      host:
        default: localhost
      port:
        default: '8081'
security:
  - BearerAuth: []
paths:
  /str/task:
    post:
      tags:
        - STR Tasks
      summary: Upload an STR task
      description: >-
        Create a new STR upload task for multiple reservations.


        ### Allowed Roles:

        `admin`, `str-uploader`


        ### Special Validation Rules:

        - Exactly one of: `amountReceived`, `cancellationAmount` must be
        provided.

        - Exactly one of: `cancellationDate`, `endDate` must be provided.

        - If `isForeigner` is true, then `guestName` and `guestId` are required.

        - If `isForeigner` is false, then `guestTaxId` is required. `guestId`
        and `guestName` are ignored.

        - `startDate` must be before `endDate`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/StrTaskRequest'
      responses:
        '200':
          description: Task created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PostStrUploadTaskResponse'
        '400':
          description: Bad request - validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '401':
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '403':
          description: Forbidden - insufficient permissions
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
components:
  schemas:
    StrTaskRequest:
      type: object
      properties:
        draftUpload:
          type: boolean
          default: false
          example: true
        reservations:
          type: array
          items:
            $ref: '#/components/schemas/StrTaskRequestReservation'
      example:
        draftUpload: true
        reservations:
          - reservationId: HMXDBC4N22
            apartmentId: 42
            startDate: 01/02/2025
            endDate: 05/02/2025
            amountReceived: 309.83
            platform: Airbnb
            paymentMethod: Λογαριασμός Πληρωμών Ημεδαπής
            guestName: John Doe
            guestId: AT1237212
            guestTaxId: '137269544'
            isForeigner: true
    PostStrUploadTaskResponse:
      type: object
      properties:
        taskId:
          type: integer
          example: 123
        requestId:
          type: string
          example: a1b2c3d4-e5f6-7890-a1b2-c3d4e5f67890
        createdAt:
          type: string
          format: date-time
          example: '2022-01-01T00:00:00Z'
    ErrorResponse:
      type: object
      properties:
        errorMessage:
          type: string
        requestId:
          type: string
    StrTaskRequestReservation:
      type: object
      required:
        - apartmentId
        - endDate
        - isForeigner
        - paymentMethod
        - platform
        - reservationId
        - startDate
      properties:
        reservationId:
          type: string
          example: HMXDBC4N22
        apartmentId:
          type: integer
          example: 42
        startDate:
          type: string
          example: 01/02/2025
        endDate:
          type: string
          example: 05/02/2025
        amountReceived:
          type: number
          format: decimal
          example: 309.83
        platform:
          $ref: '#/components/schemas/Platform'
        paymentMethod:
          $ref: '#/components/schemas/PaymentMethod'
        guestName:
          type: string
          example: John Doe
        guestId:
          type: string
          example: AT1237212
        guestTaxId:
          type: string
          example: '137269544'
        isForeigner:
          type: boolean
          example: true
        cancellationDate:
          type: string
        cancellationAmount:
          type: number
          format: decimal
    Platform:
      type: string
      enum:
        - Airbnb
        - Booking.com
        - Clickstay
        - Homestay
        - Luxury Retreats
        - Only-apartments
        - TripAdvisor
        - λλες ψηφιακές πλατφόρμες
    PaymentMethod:
      type: string
      enum:
        - Λογαριασμός Πληρωμών Ημεδαπής
        - Λογαριασμός Πληρωμών Αλλοδαπής
        - Μετρητά
        - Λοιποί
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: >-
        JWT Authorization header using the Bearer scheme. Example:
        "Authorization: Bearer {token}"

````