openapi: 3.1.0
info:
  title: KATSANA API
  version: 1.0.0
  description: "Access vehicles, locations, fleets and trip history with KATSANA API V1. Sign in with
    POST /auth and send the returned token in the Authorization header. Select V1 with Accept:
    application/vnd.KATSANA.v1+json; API URLs do not use a /v1 prefix."
  contact:
    name: KATSANA
    url: https://www.katsana.com
  x-scalar-sdk-installation:
    - lang: php
      description: Use the [KATSANA PHP SDK](https://github.com/katsana/katsana-sdk-php). See the [SDK
        guide](/guides/sdks/) for token configuration, version compatibility, endpoint coverage and
        method/path differences.
    - lang: laravel
      description: The existing [Laravel integration](https://github.com/katsana/katsana-sdk-laravel)
        wraps the PHP SDK. Read the [SDK guide](/guides/sdks/) for version and dependency notes.
    - lang: swift
      description: Use the existing [iOS/macOS SDK](https://github.com/katsana/katsana-sdk-ios). The v3
        branch is development work; see [SDK status](/guides/sdks/) before choosing a version.
servers:
  - url: https://api.katsana.com
    description: KATSANA API; select V1 through the Accept header.
tags:
  - name: Authentication
    description: Sign in with POST /auth to get an access token.
  - name: Account
    description: Profile and notifications.
  - name: Vehicles
    description: Accessible vehicles and metadata.
  - name: Locations
    description: Current and historical positions.
  - name: Fleets
    description: Fleets, drivers and vehicle membership.
  - name: Checkpoints
    description: Checkpoints resources.
  - name: Positions
    description: Positions resources.
  - name: Daily summaries
    description: Daily summaries resources.
  - name: Track statistics
    description: Track statistics resources.
  - name: Travels
    description: Travels resources.
  - name: Travel summaries
    description: Lightweight trip summaries.
  - name: Sharing
    description: Time-limited private vehicle links.
  - name: Driver logs
    description: Fuel records and driver reports.
  - name: Assistance
    description: Vehicle assistance dispatch and emergency-contact shares.
  - name: Video operations
    description: MDVR live streams and stored video access.
  - name: Subscriptions
    description: Vehicle subscription status, renewal billing and support notifications.
security:
  - ApiToken: []
paths:
  /auth:
    post:
      operationId: createJwtToken
      summary: Sign in and get a token
      tags:
        - Authentication
      description: Sign in with your account email as username and your password in a JSON body. The email
        alias is also accepted. A successful response fills the API token field in this reference
        automatically; protected requests then send that token in the Authorization header. Send
        both credentials; missing values are not consistently validated. See the [authentication
        guide](/guides/authentication/) for token handling and browser request availability.
      security: []
      parameters:
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JwtToken"
        "401":
          description: Invalid credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JwtError"
        "500":
          description: Token creation failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/JwtError"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                username:
                  type: string
                  description: Account email; alias email is also accepted.
                email:
                  type: string
                password:
                  type: string
                  format: password
                  writeOnly: true
              required:
                - password
              anyOf:
                - required:
                    - username
                - required:
                    - email
              example:
                username: developer@example.com
                password: <password>
            example:
              username: <your-email>
              password: <your-password>
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/auth' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header 'Content-Type: application/json' \
              --data '{"username":"<your-email>","password":"<password>"}'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = JSON.stringify({
              "username": "<your-email>",
              "password": "<password>"
            });
            const response = await fetch("https://api.katsana.com/auth", {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Content-Type": "application/json"
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /profile:
    get:
      operationId: getProfile
      summary: Get your profile
      tags:
        - Account
      description: ""
      security:
        - ApiToken: []
      parameters:
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: fleets, plan, company, operations_subscription."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Profile"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/profile' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/profile", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
    patch:
      operationId: updateProfile
      summary: Update your profile
      tags:
        - Account
      description: Only supplied fields are updated. Supplied fullname/address/state/country/contact
        fields may not be empty; phone values use platform phone validation. This operation changes
        data.
      security:
        - ApiToken: []
      parameters:
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Profile"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "422":
          description: Profile field validation failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationErrors"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                fullname:
                  type: string
                gender:
                  type: string
                  description: Accepted keys come from the platform gender configuration; no new enum is assumed.
                address:
                  type: string
                postcode:
                  type: string
                  minLength: 3
                  maxLength: 6
                state:
                  type: string
                country:
                  type: string
                phone_home:
                  type: string
                phone_mobile:
                  type: string
                emergency_fullname:
                  type: string
                emergency_phone_home:
                  type: string
                emergency_phone_mobile:
                  type: string
              example:
                fullname: Example Developer
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request PATCH 'https://api.katsana.com/profile' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"fullname":"Example Developer"}'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = JSON.stringify({
              "fullname": "Example Developer"
            });
            const response = await fetch("https://api.katsana.com/profile", {
              method: "PATCH",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /profile/avatar:
    post:
      operationId: uploadProfileAvatar
      summary: Upload your avatar
      tags:
        - Account
      description: Uploads a new profile avatar.
      security:
        - ApiToken: []
      parameters:
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Avatar"
        "400":
          description: Unable to open upload.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "422":
          description: Image is missing, invalid or larger than 1000 KiB.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationErrors"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "500":
          description: Image storage failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                  description: Image file, at most 1000 KiB under Laravel image validation.
              required:
                - file
              example:
                file: /path/to/image.png
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/profile/avatar' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --form 'file=@/path/to/image.png'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            import { readFile } from 'node:fs/promises';
            const body = new FormData();
            // Select a local image file for file.
            body.append("file", new Blob([await readFile("/path/to/image.png")]), 'image.png');
            const response = await fetch("https://api.katsana.com/profile/avatar", {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/avatar:
    post:
      operationId: uploadVehicleAvatar
      summary: Upload vehicle avatar
      tags:
        - Vehicles
      description: Uploads a new vehicle avatar.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Avatar"
        "400":
          description: Unable to open upload.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "422":
          description: Image is missing, invalid or larger than 1000 KiB.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationErrors"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "500":
          description: Image storage failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                file:
                  type: string
                  format: binary
                  description: Image file, at most 1000 KiB under Laravel image validation.
              required:
                - file
              example:
                file: /path/to/image.png
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/vehicles/1001/avatar' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --form 'file=@/path/to/image.png'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            import { readFile } from 'node:fs/promises';
            const body = new FormData();
            // Select a local image file for file.
            body.append("file", new Blob([await readFile("/path/to/image.png")]), 'image.png');
            const response = await fetch("https://api.katsana.com/vehicles/1001/avatar", {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles:
    get:
      operationId: listVehicles
      summary: List accessible vehicles
      tags:
        - Vehicles
      description: ""
      security:
        - ApiToken: []
      parameters:
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: page
          in: query
          required: false
          schema:
            type: integer
          description: Supplying page enables pagination. Without it, all accessible records are returned.
        - name: per_page
          in: query
          required: false
          schema:
            type: integer
            default: 100
          description: Page size, used only when page is supplied. No universal maximum is established.
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: fleets, tags, features, score, movement, temperature,
            online, addons, regulation, drivemark."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VehicleList"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}:
    get:
      operationId: getVehicle
      summary: Get a vehicle
      tags:
        - Vehicles
      description: ""
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: fleets, tags, features, score, movement, temperature,
            online, addons, regulation, drivemark."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VehicleEnvelope"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
    patch:
      operationId: updateVehicle
      summary: Update a vehicle
      tags:
        - Vehicles
      description: Requires vehicle update permission. license_plate takes precedence over the legacy
        vehicle_number field. Updating manufacturer/model can update description when no explicit
        description is provided. This operation changes data.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VehicleEnvelope"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "422":
          description: Vehicle field validation failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationErrors"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                vehicle_number:
                  type: string
                  minLength: 2
                license_plate:
                  type: string
                  minLength: 2
                description:
                  type: string
                  minLength: 4
                manufacturer:
                  type: string
                  minLength: 2
                model:
                  type: string
                  minLength: 2
                insured_by: {}
                insured_expiry:
                  type: string
                  description: Parsed as a date by the platform. The full set of accepted input formats is not
                    specified.
              example:
                description: Example vehicle
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request PATCH 'https://api.katsana.com/vehicles/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"description":"Example vehicle"}'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = JSON.stringify({
              "description": "Example vehicle"
            });
            const response = await fetch("https://api.katsana.com/vehicles/1001", {
              method: "PATCH",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/location:
    get:
      operationId: getVehicleLocation
      summary: Get current vehicle location
      tags:
        - Locations
      description: Private no-cache response. Data comes from the current tracking provider.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Location"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/location' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/location", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /fleets:
    get:
      operationId: listFleets
      summary: List accessible fleets
      tags:
        - Fleets
      description: ""
      security:
        - ApiToken: []
      parameters:
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: page
          in: query
          required: false
          schema:
            type: integer
          description: Supplying page enables pagination. Without it, all accessible records are returned.
        - name: per_page
          in: query
          required: false
          schema:
            type: integer
            default: 100
          description: Page size, used only when page is supplied. No universal maximum is established.
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: managers."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FleetList"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/fleets' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/fleets", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /fleets/{fleet}:
    get:
      operationId: getFleet
      summary: Get a fleet
      tags:
        - Fleets
      description: ""
      security:
        - ApiToken: []
      parameters:
        - name: fleet
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: managers."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FleetEnvelope"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/fleets/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/fleets/1001", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /fleets/{fleet}/drivers:
    get:
      operationId: listDriversInFleet
      summary: List drivers in a fleet
      tags:
        - Fleets
      description: ""
      security:
        - ApiToken: []
      parameters:
        - name: fleet
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: page
          in: query
          required: false
          schema:
            type: integer
          description: Supplying page enables pagination. Without it, all accessible records are returned.
        - name: per_page
          in: query
          required: false
          schema:
            type: integer
            default: 100
          description: Page size, used only when page is supplied. No universal maximum is established.
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: fleet_id, profile."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DriverList"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/fleets/1001/drivers' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/fleets/1001/drivers", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
    post:
      operationId: createFleetDriver
      summary: Create a fleet driver
      tags:
        - Fleets
      description: Requires fleet update permission. identification_type defaults to mykad. Do not send
        biometric data from a public documentation client. This operation changes data.
      security:
        - ApiToken: []
      parameters:
        - name: fleet
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DriverEnvelope"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "422":
          description: Driver validation failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationErrors"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                fullname:
                  type: string
                identification:
                  type:
                    - string
                    - "null"
                identification_type:
                  type: string
                  enum:
                    - mykad
                fingerprint:
                  type: array
                  minItems: 1
                  maxItems: 2
                  items:
                    type: string
                    description: Encoded fingerprint data; no biometric example is included.
              required:
                - fullname
              example:
                fullname: Example Driver
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/fleets/1001/drivers' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"fullname":"Example Driver"}'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = JSON.stringify({
              "fullname": "Example Driver"
            });
            const response = await fetch("https://api.katsana.com/fleets/1001/drivers", {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /fleets/{fleet}/vehicles:
    get:
      operationId: listVehiclesInFleet
      summary: List vehicles in a fleet
      tags:
        - Fleets
      description: ""
      security:
        - ApiToken: []
      parameters:
        - name: fleet
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: page
          in: query
          required: false
          schema:
            type: integer
          description: Supplying page enables pagination. Without it, all accessible records are returned.
        - name: per_page
          in: query
          required: false
          schema:
            type: integer
            default: 100
          description: Page size, used only when page is supplied. No universal maximum is established.
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: fleets, tags, features, score, movement, temperature,
            online, addons, regulation, drivemark."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VehicleList"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/fleets/1001/vehicles' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/fleets/1001/vehicles", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /fleets/{fleet}/drivers/{driver}:
    patch:
      operationId: updateFleetDriver
      summary: Update a fleet driver
      tags:
        - Fleets
      description: Requires fleet update permission. fullname remains required. An omitted identification
        is set to null by this implementation. PHP SDK v1.2.9 sends POST here; use PATCH directly
        until that SDK is corrected. This operation changes data.
      security:
        - ApiToken: []
      parameters:
        - name: driver
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: fleet
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DriverEnvelope"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "422":
          description: Driver validation failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationErrors"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                fullname:
                  type: string
                identification:
                  type:
                    - string
                    - "null"
                identification_type:
                  type: string
                  enum:
                    - mykad
                fingerprint:
                  type: array
                  minItems: 1
                  maxItems: 2
                  items:
                    type: string
                    description: Encoded fingerprint data; no biometric example is included.
              required:
                - fullname
              example:
                fullname: Example Driver
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request PATCH 'https://api.katsana.com/fleets/1001/drivers/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"fullname":"Example Driver"}'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = JSON.stringify({
              "fullname": "Example Driver"
            });
            const response = await fetch("https://api.katsana.com/fleets/1001/drivers/1001", {
              method: "PATCH",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/checkpoints:
    get:
      operationId: getCheckpointsDefault
      summary: Get checkpoints · default
      tags:
        - Checkpoints
      description: Alias for today. Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Checkpoint"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/checkpoints' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/checkpoints", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/checkpoints/today:
    get:
      operationId: getCheckpointsToday
      summary: Get checkpoints · today
      tags:
        - Checkpoints
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Checkpoint"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/checkpoints/today' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await fetch("https://api.katsana.com/vehicles/1001/checkpoints/today",
            {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/checkpoints/yesterday:
    get:
      operationId: getCheckpointsYesterday
      summary: Get checkpoints · yesterday
      tags:
        - Checkpoints
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Checkpoint"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/checkpoints/yesterday' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/checkpoints/yesterday", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/checkpoints/duration:
    get:
      operationId: getCheckpointsRange
      summary: Get checkpoints · range
      tags:
        - Checkpoints
      description: Calendar boundaries use the vehicle timezone. The supplied start is rounded to start of
        its day; the supplied end is rounded to start of its day plus one day.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: start
          in: query
          required: false
          schema:
            type: string
          description: Range start parsed in timezone (device timezone by default).
        - name: end
          in: query
          required: false
          schema:
            type: string
          description: Range end parsed in timezone (device timezone by default).
        - name: timezone
          in: query
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: IANA timezone overriding the device timezone for range parsing.
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Checkpoint"
        "400":
          description: Invalid date input.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/checkpoints/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/checkpoints/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/checkpoints/{year}/{month}/{day}:
    get:
      operationId: getCheckpointsDate
      summary: Get checkpoints · date
      tags:
        - Checkpoints
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: day
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-3]?[0-9]$
            examples:
              - "15"
          description: "Route syntax only: one digit, optionally preceded by 0–3. Use a real calendar day;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: month
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0|1]?[0-9]$
            examples:
              - "01"
          description: "Route syntax only: the month pattern accepts 0, 1 or a literal | before a digit. Use a
            real calendar month; calendar validity is not separately enforced here and Carbon may
            normalize overflowing values."
        - name: year
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-9]{4}$
            examples:
              - "2026"
          description: "Route syntax only: four digits, including leading zeros. Use a real calendar year;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Checkpoint"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/checkpoints/2026/01/15' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/checkpoints/2026/01/15", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/checkpoints/{year}/{month}:
    get:
      operationId: getCheckpointsMonth
      summary: Get checkpoints · month
      tags:
        - Checkpoints
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: month
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0|1]?[0-9]$
            examples:
              - "01"
          description: "Route syntax only: the month pattern accepts 0, 1 or a literal | before a digit. Use a
            real calendar month; calendar validity is not separately enforced here and Carbon may
            normalize overflowing values."
        - name: year
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-9]{4}$
            examples:
              - "2026"
          description: "Route syntax only: four digits, including leading zeros. Use a real calendar year;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Checkpoint"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/checkpoints/2026/01' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/checkpoints/2026/01", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/positions:
    get:
      operationId: getPositionsDefault
      summary: Get positions · default
      tags:
        - Positions
      description: Alias for today. Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: speed, odometer, place, altitude, distance, course,
            fuel, ignition, temperature, voltage, connectivity, driver, harsh, custom,
            device_battery."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Positions"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/positions' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/positions", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/positions/today:
    get:
      operationId: getPositionsToday
      summary: Get positions · today
      tags:
        - Positions
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: speed, odometer, place, altitude, distance, course,
            fuel, ignition, temperature, voltage, connectivity, driver, harsh, custom,
            device_battery."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Positions"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/positions/today' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/positions/today", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/positions/yesterday:
    get:
      operationId: getPositionsYesterday
      summary: Get positions · yesterday
      tags:
        - Positions
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: speed, odometer, place, altitude, distance, course,
            fuel, ignition, temperature, voltage, connectivity, driver, harsh, custom,
            device_battery."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Positions"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/positions/yesterday' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/positions/yesterday", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/positions/duration:
    get:
      operationId: getPositionsRange
      summary: Get positions · range
      tags:
        - Positions
      description: Calendar boundaries use the vehicle timezone. Rejects ranges whose diffInHours exceeds
        24 with 416.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: start
          in: query
          required: false
          schema:
            type: string
          description: Range start parsed in timezone (device timezone by default).
        - name: end
          in: query
          required: false
          schema:
            type: string
          description: Range end parsed in timezone (device timezone by default).
        - name: timezone
          in: query
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: IANA timezone overriding the device timezone for range parsing.
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: speed, odometer, place, altitude, distance, course,
            fuel, ignition, temperature, voltage, connectivity, driver, harsh, custom,
            device_battery."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Positions"
        "400":
          description: Invalid date input.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "416":
          description: Requested history range is too wide.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/positions/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/positions/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/positions/{year}/{month}/{day}:
    get:
      operationId: getPositionsDate
      summary: Get positions · date
      tags:
        - Positions
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: day
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-3]?[0-9]$
            examples:
              - "15"
          description: "Route syntax only: one digit, optionally preceded by 0–3. Use a real calendar day;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: month
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0|1]?[0-9]$
            examples:
              - "01"
          description: "Route syntax only: the month pattern accepts 0, 1 or a literal | before a digit. Use a
            real calendar month; calendar validity is not separately enforced here and Carbon may
            normalize overflowing values."
        - name: year
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-9]{4}$
            examples:
              - "2026"
          description: "Route syntax only: four digits, including leading zeros. Use a real calendar year;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: speed, odometer, place, altitude, distance, course,
            fuel, ignition, temperature, voltage, connectivity, driver, harsh, custom,
            device_battery."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Positions"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/positions/2026/01/15' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/positions/2026/01/15", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/summaries:
    get:
      operationId: getSummariesDefault
      summary: Get daily summaries · default
      tags:
        - Daily summaries
      description: Alias for today. Calendar boundaries use the vehicle timezone. Single-day queries
        return a summary object or an empty array; month/range queries return an array.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: drivemark, violation_details, costing."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/DailySummary"
                  - type: array
                    maxItems: 0
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/summaries' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/summaries", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/summaries/today:
    get:
      operationId: getSummariesToday
      summary: Get daily summaries · today
      tags:
        - Daily summaries
      description: Calendar boundaries use the vehicle timezone. Single-day queries return a summary
        object or an empty array; month/range queries return an array.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: drivemark, violation_details, costing."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/DailySummary"
                  - type: array
                    maxItems: 0
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/summaries/today' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/summaries/today", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/summaries/yesterday:
    get:
      operationId: getSummariesYesterday
      summary: Get daily summaries · yesterday
      tags:
        - Daily summaries
      description: Calendar boundaries use the vehicle timezone. Single-day queries return a summary
        object or an empty array; month/range queries return an array.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: drivemark, violation_details, costing."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/DailySummary"
                  - type: array
                    maxItems: 0
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/summaries/yesterday' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/summaries/yesterday", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/summaries/duration:
    get:
      operationId: getSummariesRange
      summary: Get daily summaries · range
      tags:
        - Daily summaries
      description: Calendar boundaries use the vehicle timezone. The supplied start is rounded to start of
        its day; the supplied end is rounded to start of its day plus one day. Single-day queries
        return a summary object or an empty array; month/range queries return an array.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: start
          in: query
          required: false
          schema:
            type: string
          description: Range start parsed in timezone (device timezone by default).
        - name: end
          in: query
          required: false
          schema:
            type: string
          description: Range end parsed in timezone (device timezone by default).
        - name: timezone
          in: query
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: IANA timezone overriding the device timezone for range parsing.
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: drivemark, violation_details, costing."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/DailySummary"
        "400":
          description: Invalid date input.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/summaries/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/summaries/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/summaries/{year}/{month}/{day}:
    get:
      operationId: getSummariesDate
      summary: Get daily summaries · date
      tags:
        - Daily summaries
      description: Calendar boundaries use the vehicle timezone. Single-day queries return a summary
        object or an empty array; month/range queries return an array.
      security:
        - ApiToken: []
      parameters:
        - name: day
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-3]?[0-9]$
            examples:
              - "15"
          description: "Route syntax only: one digit, optionally preceded by 0–3. Use a real calendar day;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: month
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0|1]?[0-9]$
            examples:
              - "01"
          description: "Route syntax only: the month pattern accepts 0, 1 or a literal | before a digit. Use a
            real calendar month; calendar validity is not separately enforced here and Carbon may
            normalize overflowing values."
        - name: year
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-9]{4}$
            examples:
              - "2026"
          description: "Route syntax only: four digits, including leading zeros. Use a real calendar year;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: drivemark, violation_details, costing."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/DailySummary"
                  - type: array
                    maxItems: 0
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/summaries/2026/01/15' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/summaries/2026/01/15", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/summaries/{year}/{month}:
    get:
      operationId: getSummariesMonth
      summary: Get daily summaries · month
      tags:
        - Daily summaries
      description: Calendar boundaries use the vehicle timezone. Single-day queries return a summary
        object or an empty array; month/range queries return an array.
      security:
        - ApiToken: []
      parameters:
        - name: month
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0|1]?[0-9]$
            examples:
              - "01"
          description: "Route syntax only: the month pattern accepts 0, 1 or a literal | before a digit. Use a
            real calendar month; calendar validity is not separately enforced here and Carbon may
            normalize overflowing values."
        - name: year
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-9]{4}$
            examples:
              - "2026"
          description: "Route syntax only: four digits, including leading zeros. Use a real calendar year;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: drivemark, violation_details, costing."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/DailySummary"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/summaries/2026/01' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await fetch("https://api.katsana.com/vehicles/1001/summaries/2026/01",
            {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/tracks:
    get:
      operationId: getTracksDefault
      summary: Get track statistics · default
      tags:
        - Track statistics
      description: Alias for today. Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TrackSummary"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/tracks' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/tracks", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/tracks/today:
    get:
      operationId: getTracksToday
      summary: Get track statistics · today
      tags:
        - Track statistics
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TrackSummary"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/tracks/today' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/tracks/today", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/tracks/yesterday:
    get:
      operationId: getTracksYesterday
      summary: Get track statistics · yesterday
      tags:
        - Track statistics
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TrackSummary"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/tracks/yesterday' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/tracks/yesterday", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/tracks/duration:
    get:
      operationId: getTracksRange
      summary: Get track statistics · range
      tags:
        - Track statistics
      description: Calendar boundaries use the vehicle timezone. Rejects ranges whose diffInHours exceeds
        24 with 416.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: start
          in: query
          required: false
          schema:
            type: string
          description: Range start parsed in timezone (device timezone by default).
        - name: end
          in: query
          required: false
          schema:
            type: string
          description: Range end parsed in timezone (device timezone by default).
        - name: timezone
          in: query
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: IANA timezone overriding the device timezone for range parsing.
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TrackSummary"
        "400":
          description: Invalid date input.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "416":
          description: Requested history range is too wide.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/tracks/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/tracks/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/tracks/{year}/{month}/{day}:
    get:
      operationId: getTracksDate
      summary: Get track statistics · date
      tags:
        - Track statistics
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: day
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-3]?[0-9]$
            examples:
              - "15"
          description: "Route syntax only: one digit, optionally preceded by 0–3. Use a real calendar day;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: month
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0|1]?[0-9]$
            examples:
              - "01"
          description: "Route syntax only: the month pattern accepts 0, 1 or a literal | before a digit. Use a
            real calendar month; calendar validity is not separately enforced here and Carbon may
            normalize overflowing values."
        - name: year
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-9]{4}$
            examples:
              - "2026"
          description: "Route syntax only: four digits, including leading zeros. Use a real calendar year;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TrackSummary"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/tracks/2026/01/15' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await fetch("https://api.katsana.com/vehicles/1001/tracks/2026/01/15",
            {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/travels:
    get:
      operationId: getTravelsDefault
      summary: Get travels · default
      tags:
        - Travels
      description: Alias for today. Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: type, drivemark."
        - name: excludes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated removable fields: histories."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Travels"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/travels", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/travels/today:
    get:
      operationId: getTravelsToday
      summary: Get travels · today
      tags:
        - Travels
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: type, drivemark."
        - name: excludes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated removable fields: histories."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Travels"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/today' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/travels/today", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/travels/yesterday:
    get:
      operationId: getTravelsYesterday
      summary: Get travels · yesterday
      tags:
        - Travels
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: type, drivemark."
        - name: excludes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated removable fields: histories."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Travels"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/yesterday' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await fetch("https://api.katsana.com/vehicles/1001/travels/yesterday",
            {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/travels/duration:
    get:
      operationId: getTravelsRange
      summary: Get travels · range
      tags:
        - Travels
      description: Calendar boundaries use the vehicle timezone. Rejects ranges whose diffInHours exceeds
        48 with 416.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: start
          in: query
          required: false
          schema:
            type: string
          description: Range start parsed in timezone (device timezone by default).
        - name: end
          in: query
          required: false
          schema:
            type: string
          description: Range end parsed in timezone (device timezone by default).
        - name: timezone
          in: query
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: IANA timezone overriding the device timezone for range parsing.
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: type, drivemark."
        - name: excludes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated removable fields: histories."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Travels"
        "400":
          description: Invalid date input.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "416":
          description: Requested history range is too wide.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/travels/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/travels/{year}/{month}/{day}:
    get:
      operationId: getTravelsDate
      summary: Get travels · date
      tags:
        - Travels
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: day
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-3]?[0-9]$
            examples:
              - "15"
          description: "Route syntax only: one digit, optionally preceded by 0–3. Use a real calendar day;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: month
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0|1]?[0-9]$
            examples:
              - "01"
          description: "Route syntax only: the month pattern accepts 0, 1 or a literal | before a digit. Use a
            real calendar month; calendar validity is not separately enforced here and Carbon may
            normalize overflowing values."
        - name: year
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-9]{4}$
            examples:
              - "2026"
          description: "Route syntax only: four digits, including leading zeros. Use a real calendar year;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: type, drivemark."
        - name: excludes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated removable fields: histories."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Travels"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/2026/01/15' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await fetch("https://api.katsana.com/vehicles/1001/travels/2026/01/15",
            {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/travels/summaries:
    get:
      operationId: getTravelsSummariesDefault
      summary: Get travel summaries · default
      tags:
        - Travel summaries
      description: Alias for today. Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: start, end, drivemark, type, driver, odometer."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TravelSummary"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/summaries' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await fetch("https://api.katsana.com/vehicles/1001/travels/summaries",
            {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/travels/summaries/today:
    get:
      operationId: getTravelsSummariesToday
      summary: Get travel summaries · today
      tags:
        - Travel summaries
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: start, end, drivemark, type, driver, odometer."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TravelSummary"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/summaries/today' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/travels/summaries/today", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/travels/summaries/yesterday:
    get:
      operationId: getTravelsSummariesYesterday
      summary: Get travel summaries · yesterday
      tags:
        - Travel summaries
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: start, end, drivemark, type, driver, odometer."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TravelSummary"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/summaries/yesterday' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/travels/summaries/yesterday", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/travels/summaries/duration:
    get:
      operationId: getTravelsSummariesRange
      summary: Get travel summaries · range
      tags:
        - Travel summaries
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: start
          in: query
          required: false
          schema:
            type: string
          description: Range start parsed in timezone (device timezone by default).
        - name: end
          in: query
          required: false
          schema:
            type: string
          description: Range end parsed in timezone (device timezone by default).
        - name: timezone
          in: query
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: IANA timezone overriding the device timezone for range parsing.
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: start, end, drivemark, type, driver, odometer."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TravelSummary"
        "400":
          description: Invalid date input.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/summaries/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/travels/summaries/duration?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/travels/summaries/{year}/{month}/{day}:
    get:
      operationId: getTravelsSummariesDate
      summary: Get travel summaries · date
      tags:
        - Travel summaries
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: day
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-3]?[0-9]$
            examples:
              - "15"
          description: "Route syntax only: one digit, optionally preceded by 0–3. Use a real calendar day;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: month
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0|1]?[0-9]$
            examples:
              - "01"
          description: "Route syntax only: the month pattern accepts 0, 1 or a literal | before a digit. Use a
            real calendar month; calendar validity is not separately enforced here and Carbon may
            normalize overflowing values."
        - name: year
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-9]{4}$
            examples:
              - "2026"
          description: "Route syntax only: four digits, including leading zeros. Use a real calendar year;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: start, end, drivemark, type, driver, odometer."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TravelSummary"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: >-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/summaries/2026/01/15'
            \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/travels/summaries/2026/01/15", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/travels/summaries/{year}/{month}:
    get:
      operationId: getTravelsSummariesMonth
      summary: Get travel summaries · month
      tags:
        - Travel summaries
      description: Calendar boundaries use the vehicle timezone.
      security:
        - ApiToken: []
      parameters:
        - name: month
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0|1]?[0-9]$
            examples:
              - "01"
          description: "Route syntax only: the month pattern accepts 0, 1 or a literal | before a digit. Use a
            real calendar month; calendar validity is not separately enforced here and Carbon may
            normalize overflowing values."
        - name: year
          in: path
          required: true
          schema:
            type: string
            pattern: ^[0-9]{4}$
            examples:
              - "2026"
          description: "Route syntax only: four digits, including leading zeros. Use a real calendar year;
            calendar validity is not separately enforced here and Carbon may normalize overflowing
            values."
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: start, end, drivemark, type, driver, odometer."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/TravelSummary"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/summaries/2026/01' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/travels/summaries/2026/01", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/travels/{id}:
    get:
      operationId: getTravel
      summary: Get one travel
      tags:
        - Travels
      description: Returns one trip with drivemark requested by the controller.
      security:
        - ApiToken: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: includes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated optional fields: type, drivemark."
        - name: excludes
          in: query
          required: false
          schema:
            type: string
          description: "Comma-separated removable fields: histories."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Trip"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/travels/1001", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/travels/summaries/{id}:
    patch:
      operationId: updateTravelSummary
      summary: Update a travel type
      tags:
        - Travel summaries
      description: Updates the travel type.
      security:
        - ApiToken: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TravelSummary"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "422":
          description: type is required and must be a string.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationErrors"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                type:
                  type: string
                  description: The controller accepts a string; no enum is enforced.
              required:
                - type
              example:
                type: business
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request PATCH 'https://api.katsana.com/vehicles/1001/travels/summaries/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"type":"business"}'
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const body = JSON.stringify({
              "type": "business"
            });

            const response = await
            fetch("https://api.katsana.com/vehicles/1001/travels/summaries/1001", {
              method: "PATCH",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
    get:
      operationId: getTravelSummary
      summary: Get a single travel summary — known failure
      tags:
        - Travel summaries
      description: "This endpoint currently returns a server error after vehicle authorization: the action
        calls trips() on the route string rather than the resolved device. Use the travel-summary
        list endpoints to retrieve summaries. Authentication, vehicle access, vehicle-not-found and
        throttling errors can occur before this failure."
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: id
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
      responses:
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The account is not permitted to view this vehicle.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Vehicle not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "500":
          description: Server error after vehicle authorization. The error body and debug detail depend on the
            server configuration.
      x-known-issue:
        id: travel-summary-route-argument
        status: known-broken
        successfulResponseDocumented: false
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/travels/summaries/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/vehicles/1001/travels/summaries/1001", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/sharing:
    get:
      operationId: listVehicleShares
      summary: List your active vehicle shares
      tags:
        - Sharing
      description: Only active shares belonging to the authenticated user for this vehicle are returned.
        Share tokens and URLs are credentials.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Share"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/sharing' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/sharing", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
    post:
      operationId: createVehicleShare
      summary: Create a vehicle share
      tags:
        - Sharing
      description: Creates a private, time-limited vehicle share. Treat the returned share token and URL
        as credentials.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Share"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                description:
                  type:
                    - string
                    - "null"
                duration:
                  type: string
                  description: Share duration as a platform scheduling expression. Use 1D for one day; this is the
                    default on create. The full expression grammar is not specified.
              example:
                description: Example integration
                duration: 1D
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/vehicles/1001/sharing' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"description":"Example integration","duration":"1D"}'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = JSON.stringify({
              "description": "Example integration",
              "duration": "1D"
            });
            const response = await fetch("https://api.katsana.com/vehicles/1001/sharing", {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/sharing/{share}:
    patch:
      operationId: updateVehicleShare
      summary: Update a vehicle share
      tags:
        - Sharing
      description: Changing duration recalculates expiry from the current time. Omitting description
        preserves its current value. This operation changes data.
      security:
        - ApiToken: []
      parameters:
        - name: share
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Share"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                description:
                  type:
                    - string
                    - "null"
                duration:
                  type: string
                  description: Share duration as a platform scheduling expression. Use 1D for one day; this is the
                    default on create. The full expression grammar is not specified.
              example:
                description: Example integration
                duration: 1D
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request PATCH 'https://api.katsana.com/vehicles/1001/sharing/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"description":"Example integration","duration":"1D"}'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = JSON.stringify({
              "description": "Example integration",
              "duration": "1D"
            });
            const response = await fetch("https://api.katsana.com/vehicles/1001/sharing/1001", {
              method: "PATCH",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
    delete:
      operationId: deleteVehicleShare
      summary: Delete a vehicle share
      tags:
        - Sharing
      description: Deletes the vehicle share and ends access through that share.
      security:
        - ApiToken: []
      parameters:
        - name: share
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "204":
          description: Share deleted; empty response.
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request DELETE 'https://api.katsana.com/vehicles/1001/sharing/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/sharing/1001", {
              method: "DELETE",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /drivers/vehicles/{vehicle}/fuels:
    get:
      operationId: listVehicleFuels
      summary: List fuel records
      tags:
        - Driver logs
      description: Reads start/end as device-timezone timestamps. The controller separately validates
        from_date/to_date but does not use those fields for filtering; use start/end.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
        - name: start
          in: query
          required: false
          schema:
            type: string
          description: Optional start timestamp in the vehicle timezone.
        - name: end
          in: query
          required: false
          schema:
            type: string
          description: Optional end timestamp in the vehicle timezone.
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Fuel"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/drivers/vehicles/1001/fuels?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/drivers/vehicles/1001/fuels?start=2026-01-15+00%3A00%3A00&end=2026-01-15+23%3A59%3A59", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
    post:
      operationId: createVehicleFuel
      summary: Create a fuel record
      tags:
        - Driver logs
      description: May update an existing record when platform_id is supplied or a record has the same
        tracked_at. Send litre for refuel volume; the output is refuel_manual. This operation
        changes data.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Fuel"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "422":
          description: Fuel validation or price-per-litre calculation failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationErrors"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                odometer:
                  type: integer
                  example: 12000
                litre:
                  type: number
                  example: 20
                total_cost:
                  type: number
                price_litre:
                  type: number
                  example: 2.5
                fuel_type:
                  type: string
                  example: Diesel
                latitude:
                  type: number
                longitude:
                  type: number
                tracked_at:
                  type: string
                  description: Date/time parsed in timezone, UTC by default.
                  example: 2026-01-15 08:30:00
                timezone:
                  type: string
                notes:
                  type: string
                user_id:
                  type: integer
                  description: Optional fleet-owned driver; otherwise the current user is used.
                platform_id:
                  type: integer
                  description: On create, an existing record ID can invoke update behavior.
                receipt:
                  type: string
                  format: binary
              required:
                - odometer
                - price_litre
                - fuel_type
                - latitude
                - longitude
                - tracked_at
              example:
                odometer: 12000
                litre: 20
                price_litre: 2.5
                fuel_type: Diesel
                latitude: 0
                longitude: 0
                tracked_at: 2026-01-15 08:30:00
                timezone: UTC
              anyOf:
                - required:
                    - litre
                - required:
                    - total_cost
              description: The repository requires either litre or total_cost to calculate the other; omitting
                both produces 422. Examples use a positive volume and price; the controller itself
                validates numeric values without a positive minimum.
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/drivers/vehicles/1001/fuels' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --form 'odometer=12000' \
              --form 'litre=20' \
              --form 'price_litre=2.5' \
              --form 'fuel_type=Diesel' \
              --form 'latitude=0' \
              --form 'longitude=0' \
              --form 'tracked_at=2026-01-15 08:30:00' \
              --form 'timezone=UTC'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = new FormData();
            body.append("odometer", "12000");
            body.append("litre", "20");
            body.append("price_litre", "2.5");
            body.append("fuel_type", "Diesel");
            body.append("latitude", "0");
            body.append("longitude", "0");
            body.append("tracked_at", "2026-01-15 08:30:00");
            body.append("timezone", "UTC");
            const response = await fetch("https://api.katsana.com/drivers/vehicles/1001/fuels", {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /drivers/vehicles/{vehicle}/fuels/{fuel}:
    get:
      operationId: getVehicleFuel
      summary: Get a fuel record
      tags:
        - Driver logs
      description: ""
      security:
        - ApiToken: []
      parameters:
        - name: fuel
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Fuel"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/drivers/vehicles/1001/fuels/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await fetch("https://api.katsana.com/drivers/vehicles/1001/fuels/1001",
            {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
    post:
      operationId: updateVehicleFuel
      summary: Update a fuel record
      tags:
        - Driver logs
      description: The API intentionally uses POST for this update. This operation changes data.
      security:
        - ApiToken: []
      parameters:
        - name: fuel
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Fuel"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "422":
          description: Fuel validation or price-per-litre calculation failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationErrors"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                odometer:
                  type: integer
                  example: 12000
                litre:
                  type: number
                  example: 20
                total_cost:
                  type: number
                price_litre:
                  type: number
                  example: 2.5
                fuel_type:
                  type: string
                  example: Diesel
                latitude:
                  type: number
                longitude:
                  type: number
                tracked_at:
                  type: string
                  description: Date/time parsed in timezone, UTC by default.
                  example: 2026-01-15 08:30:00
                timezone:
                  type: string
                notes:
                  type: string
                user_id:
                  type: integer
                  description: Optional fleet-owned driver; otherwise the current user is used.
                platform_id:
                  type: integer
                  description: On create, an existing record ID can invoke update behavior.
                receipt:
                  type: string
                  format: binary
              required:
                - odometer
                - price_litre
                - fuel_type
                - latitude
                - longitude
                - tracked_at
              example:
                odometer: 12000
                litre: 20
                price_litre: 2.5
                fuel_type: Diesel
                latitude: 0
                longitude: 0
                tracked_at: 2026-01-15 08:30:00
                timezone: UTC
              anyOf:
                - required:
                    - litre
                - required:
                    - total_cost
              description: The repository requires either litre or total_cost to calculate the other; omitting
                both produces 422. Examples use a positive volume and price; the controller itself
                validates numeric values without a positive minimum.
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/drivers/vehicles/1001/fuels/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --form 'odometer=12000' \
              --form 'litre=20' \
              --form 'price_litre=2.5' \
              --form 'fuel_type=Diesel' \
              --form 'latitude=0' \
              --form 'longitude=0' \
              --form 'tracked_at=2026-01-15 08:30:00' \
              --form 'timezone=UTC'
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const body = new FormData();

            body.append("odometer", "12000");

            body.append("litre", "20");

            body.append("price_litre", "2.5");

            body.append("fuel_type", "Diesel");

            body.append("latitude", "0");

            body.append("longitude", "0");

            body.append("tracked_at", "2026-01-15 08:30:00");

            body.append("timezone", "UTC");

            const response = await fetch("https://api.katsana.com/drivers/vehicles/1001/fuels/1001",
            {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
              body,
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
    delete:
      operationId: deleteVehicleFuel
      summary: Delete a fuel record
      tags:
        - Driver logs
      description: Deletes a vehicle fuel record.
      security:
        - ApiToken: []
      parameters:
        - name: fuel
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "204":
          description: Fuel record deleted; empty response.
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request DELETE 'https://api.katsana.com/drivers/vehicles/1001/fuels/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await fetch("https://api.katsana.com/drivers/vehicles/1001/fuels/1001",
            {
              method: "DELETE",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /drivers/vehicles/{vehicle}/reports:
    get:
      operationId: listVehicleReports
      summary: List driver reports
      tags:
        - Driver logs
      description: ""
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/Report"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/drivers/vehicles/1001/reports' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/drivers/vehicles/1001/reports", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
    post:
      operationId: createVehicleReport
      summary: Create a driver report
      tags:
        - Driver logs
      description: pictures are uploaded files. Priority accepts any integer; no range is enforced. This
        operation changes data.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Report"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "422":
          description: Report validation failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationErrors"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              properties:
                message:
                  type: string
                priority:
                  type: integer
                latitude:
                  type: number
                longitude:
                  type: number
                pictures:
                  type: array
                  items:
                    type: string
                    format: binary
              required:
                - message
                - priority
              example:
                message: Example vehicle inspection note
                priority: 1
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/drivers/vehicles/1001/reports' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --form 'message=Example vehicle inspection note' \
              --form 'priority=1'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = new FormData();
            body.append("message", "Example vehicle inspection note");
            body.append("priority", "1");
            const response = await fetch("https://api.katsana.com/drivers/vehicles/1001/reports", {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /drivers/vehicles/{vehicle}/reports/{report}:
    get:
      operationId: getVehicleReport
      summary: Get a driver report
      tags:
        - Driver logs
      description: ""
      security:
        - ApiToken: []
      parameters:
        - name: report
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Report"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/drivers/vehicles/1001/reports/1001' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/drivers/vehicles/1001/reports/1001", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /drivers/vehicles/{vehicle}/fuel_types:
    get:
      operationId: getVehicleFuelTypes
      summary: Get configured fuel types
      tags:
        - Driver logs
      description: ""
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FuelTypes"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/drivers/vehicles/1001/fuel_types' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await fetch("https://api.katsana.com/drivers/vehicles/1001/fuel_types",
            {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
    patch:
      operationId: updateVehicleFuelTypes
      summary: Update configured fuel types
      tags:
        - Driver logs
      description: Updates the vehicle fuel types.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
        - name: Time-Zone
          in: header
          required: false
          schema:
            type: string
            default: Asia/Kuala_Lumpur
          description: "Output timezone for transformer-formatted dates. Reference default: Asia/Kuala_Lumpur
            (UTC+8); the API falls back to UTC when omitted. Does not set the device timezone."
      responses:
        "200":
          description: Successful response
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/FuelTypes"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The authenticated account cannot access or change this resource.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Resource not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "422":
          description: fuel_types must be a nonempty array.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ValidationErrors"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                fuel_types:
                  type: array
                  items: {}
                  minItems: 1
                  example:
                    - Diesel
                  description: Required nonempty array. The controller does not validate element types.
              required:
                - fuel_types
              example:
                fuel_types:
                  - Diesel
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request PATCH 'https://api.katsana.com/drivers/vehicles/1001/fuel_types' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"fuel_types":["Diesel"]}'
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const body = JSON.stringify({
              "fuel_types": [
                "Diesel"
              ]
            });

            const response = await fetch("https://api.katsana.com/drivers/vehicles/1001/fuel_types",
            {
              method: "PATCH",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /vehicles/{vehicle}/assist/breakdown:
    post:
      operationId: createBreakdownAssistance
      summary: Request breakdown assistance
      tags:
        - Assistance
      description: Creates a one-day private vehicle share and queues an SMS to the authenticated
        account's configured emergency mobile contact, including the share link. Requires vehicle
        view permission. A successful response confirms the controller queued the notification, not
        that an SMS was delivered. This operation has real-world side effects; use only with an
        approved account and recipient. The controller reads description without explicit field
        validation.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
      responses:
        "200":
          description: Share created and emergency-contact SMS queued.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssistanceShare"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The account is not permitted to view this vehicle.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Vehicle not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        description: Share description read from request input. Validate the value before sending.
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                description:
                  type:
                    - string
                    - "null"
                  description: Message description stored on the share. No required/string validation is declared in
                    this action.
              example:
                description: Example assistance request
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/vehicles/1001/assist/breakdown' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"description":"Example assistance request"}'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = JSON.stringify({
              "description": "Example assistance request"
            });
            const response = await fetch("https://api.katsana.com/vehicles/1001/assist/breakdown", {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/assist/emergency:
    post:
      operationId: createEmergencyAssistance
      summary: Request emergency assistance
      tags:
        - Assistance
      description: Creates a one-day private vehicle share and queues an SMS to the authenticated
        account's configured emergency mobile contact, including the share link. Requires vehicle
        view permission. A successful response confirms the controller queued the notification, not
        that an SMS was delivered. This operation has real-world side effects; use only with an
        approved account and recipient. The controller reads description without explicit field
        validation.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
      responses:
        "200":
          description: Share created and emergency-contact SMS queued.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/AssistanceShare"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The account is not permitted to view this vehicle.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Vehicle not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      requestBody:
        description: Share description read from request input. Validate the value before sending.
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                description:
                  type:
                    - string
                    - "null"
                  description: Message description stored on the share. No required/string validation is declared in
                    this action.
              example:
                description: Example assistance request
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/vehicles/1001/assist/emergency' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"description":"Example assistance request"}'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = JSON.stringify({
              "description": "Example assistance request"
            });
            const response = await fetch("https://api.katsana.com/vehicles/1001/assist/emergency", {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /operations/stream:
    get:
      operationId: listVideoStreams
      summary: List MDVR live streams
      tags:
        - Video operations
      description: Requires an accessible vehicle with supported MDVR configuration and provider access.
        This GET can authenticate with external video providers, query provider status and update
        caches while assembling access-bearing links. Account features and provider behavior depend
        on the MDVR configuration. Keep returned video links private and out of logs.
      security:
        - ApiToken: []
      parameters:
        - name: stream
          in: query
          required: false
          description: Howen stream selector read by the action; default depends on channel count. No request
            validation is declared.
          schema:
            examples:
              - 1
        - name: panel
          in: query
          required: false
          description: Howen panel selector; defaults to 0. No request validation is declared.
          schema:
            examples:
              - 0
      responses:
        "200":
          description: Response data. Examples use illustrative values.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VideoIndex"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "500":
          description: Provider/configuration or serialization failures are not normalized by this action.
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/operations/stream' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/operations/stream", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /operations/stream/show:
    get:
      operationId: getVideoStream
      summary: Get an MDVR live stream
      tags:
        - Video operations
      description: "Requires an accessible vehicle with supported MDVR configuration and provider access.
        This GET can authenticate with external video providers, query provider status and update
        caches while assembling access-bearing links. Keep returned video links private and out of
        logs. Send vehicleID and channel explicitly: the action does not validate their presence or
        types, and omitting channel can leave a placeholder in the returned link."
      security:
        - ApiToken: []
      parameters:
        - name: vehicleID
          in: query
          required: false
          description: Accessible MDVR vehicle identifier. Omission is not validated and can fail to select a
            vehicle.
          schema:
            examples:
              - 1001
        - name: channel
          in: query
          required: false
          description: Provider channel selector from the stream index. If omitted, a placeholder may remain.
          schema:
            examples:
              - 1
        - name: stream
          in: query
          required: false
          description: Howen stream selector; provider-specific.
          schema:
            examples:
              - 1
        - name: panel
          in: query
          required: false
          description: Howen panel selector; provider-specific.
          schema:
            examples:
              - 0
      responses:
        "200":
          description: Response data. Examples use illustrative values.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VideoVehicle"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: The selected vehicle has no livestream URL (including an unmatched selection). The
            controller returns the message below.
          content:
            application/json:
              schema:
                type: string
                examples:
                  - This vehicle doesnt have livestream url.
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "500":
          description: Provider, configuration or serialization failure. No fixed error body is specified.
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/operations/stream/show' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/operations/stream/show", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /operations/playback:
    get:
      operationId: listVideoPlaybacks
      summary: List MDVR playback records
      tags:
        - Video operations
      description: Lists stored playback records for vehicles available to the account with supported MDVR
        configuration. This GET can contact external MDVR providers for status and update caches;
        provider authentication and feature access are required. It does not itself request a new
        recording. Returned provider or playback access details are private.
      security:
        - ApiToken: []
      parameters: []
      responses:
        "200":
          description: Response data. Examples use illustrative values.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/VideoIndex"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "500":
          description: Provider, configuration or serialization failure. No fixed error body is specified.
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/operations/playback' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/operations/playback", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /operations/playback/{id}/download:
    get:
      operationId: downloadVideoPlayback
      summary: Download a stored playback video
      tags:
        - Video operations
      description: Requires view permission on the playback vehicle. Streams an existing file from
        configured MDVR storage as an MP4 attachment. This GET reads storage and can invoke external
        storage access. Missing playback records can cause a server error rather than a 404. File
        availability depends on the configured storage.
      security:
        - ApiToken: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
      responses:
        "200":
          description: Binary MP4 attachment from configured MDVR storage.
          headers:
            Content-Disposition:
              description: Attachment filename derived from the playback filename and extension.
              schema:
                type: string
          content:
            video/mp4:
              schema:
                type: string
                format: binary
        "401":
          description: Missing/invalid credentials, or the controller denies vehicle view with Not
            authorized!. Error serialization differs between middleware and controller.
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/ApiError"
                  - type: string
                    examples:
                      - Not authorized!
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "500":
          description: Missing playback record or storage failure. No fixed error body is specified.
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/operations/playback/1001/download' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await
            fetch("https://api.katsana.com/operations/playback/1001/download", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /operations/playback/{id}/preview:
    get:
      operationId: previewVideoPlayback
      summary: Get stored playback preview metadata
      tags:
        - Video operations
      description: Requires view permission on the playback vehicle. Missing playback records can cause a
        server error rather than a 404. The url field is assigned the PreviewVideo action object
        rather than a generated temporary URL. Its serialized value is not specified; do not assume
        it is a usable preview link. Keep any access-bearing link private. This GET can resolve
        storage and device state; external/provider behavior is not fully specified.
      security:
        - ApiToken: []
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
      responses:
        "200":
          description: Playback metadata. The url value is the serialized preview action object; do not assume
            it is a URL string.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/PlaybackPreview"
        "401":
          description: Missing/invalid credentials, or the controller denies vehicle view with Not authorized!.
          content:
            application/json:
              schema:
                anyOf:
                  - $ref: "#/components/schemas/ApiError"
                  - type: string
                    examples:
                      - Not authorized!
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "500":
          description: Missing playback record or device/storage resolution failure. No fixed error body is
            specified.
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/operations/playback/1001/preview' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: >-
            const response = await fetch("https://api.katsana.com/operations/playback/1001/preview",
            {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });

            if (!response.ok) throw new Error(`HTTP ${response.status}`);

            // Inspect the operation's response schema before parsing downloads or empty responses.

            console.log(await response.text());
  /subscriptions:
    get:
      operationId: listSubscriptions
      summary: List vehicle subscription status
      tags:
        - Subscriptions
      description: Returns the account's devices with their subscription status. The subscription field is
        currently null because detailed renewal data is disabled. Keep device identifiers private.
        Check returned values when handling expiry and provider data; exact value types and expiry
        behavior are not fully specified.
      security:
        - ApiToken: []
      parameters: []
      responses:
        "200":
          description: Response data. Examples use illustrative values.
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: "#/components/schemas/SubscriptionDevice"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "500":
          description: Device, subscription or date processing failed. No fixed error body is specified.
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/subscriptions' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/subscriptions", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /subscriptions/pay:
    post:
      operationId: paySubscriptions
      summary: Create a subscription renewal bill
      tags:
        - Subscriptions
      description: Creates a pending renewal transaction, updates subscription start/duration/end metadata
        and transaction links, then creates an external Billplz bill using the account's contact
        details. This starts a payment flow and does not itself confirm payment. Each selected
        subscription must belong to the account. subscription defaults to an empty array and period
        to 1; the action applies no explicit field validator. Check both fields before sending. The
        response is the raw Transaction model, not a pay_url wrapper.
      security:
        - ApiToken: []
      parameters: []
      responses:
        "200":
          description: Raw created transaction model after the external bill call succeeds.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SubscriptionTransaction"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: A selected subscription is not owned by the authenticated account.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: A selected subscription cannot be found by the repository.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "500":
          description: Input, transaction or provider processing failed. No fixed validation-error status or
            body is specified.
      requestBody:
        description: JSON request example. The action also reads ordinary request input and does not enforce
          required fields.
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                subscription:
                  type: array
                  items: {}
                  description: Subscription IDs selected for renewal. The controller iterates these and checks
                    ownership; element-type validation is not declared.
                period:
                  description: Renewal multiplier stored as a duration in years and used in amount calculation;
                    defaults to 1. No integer, minimum or allowed-value validation is declared.
              example:
                subscription:
                  - 1001
                period: 1
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/subscriptions/pay' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"subscription":[1001],"period":1}'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = JSON.stringify({
              "subscription": [
                1001
              ],
              "period": 1
            });
            const response = await fetch("https://api.katsana.com/subscriptions/pay", {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /subscriptions/notify:
    post:
      operationId: notifySubscriptionSupport
      summary: Request subscription renewal support
      tags:
        - Subscriptions
      description: Queues a renewal-support email using the account's identity and contact details. Pass
        device as a list of device IDs; the job loads those devices and classifies terminated or
        unsubscribed vehicles. A successful response confirms dispatch, not email delivery. The
        action applies no explicit field validator or per-device ownership check; send only devices
        the account is authorized to manage.
      security:
        - ApiToken: []
      parameters: []
      responses:
        "200":
          description: Job dispatch returned; email delivery is not confirmed.
          content:
            text/html:
              schema:
                type: string
                const: Successful notified!
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "500":
          description: Dispatch or synchronous job/input failure; asynchronous job failures may occur after
            the response.
      requestBody:
        description: Device selection read from request input. The action does not enforce required fields.
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                device:
                  type: array
                  items: {}
                  description: Device IDs passed to the queued job's whereIn query. No required, array or element-type
                    validation is declared by the action.
              example:
                device:
                  - 1001
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request POST 'https://api.katsana.com/subscriptions/notify' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN" \
              --header 'Content-Type: application/json' \
              --data '{"device":[1001]}'
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const body = JSON.stringify({
              "device": [
                1001
              ]
            });
            const response = await fetch("https://api.katsana.com/subscriptions/notify", {
              method: "POST",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`,
                "Content-Type": "application/json"
              },
              body,
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
  /vehicles/{vehicle}/beacon:
    get:
      operationId: getVehicleBeacon
      summary: Get vehicle tracker and SIM information
      tags:
        - Vehicles
      description: Returns tracker and SIM provider fields for a vehicle the account can view. Keep device
        and SIM identifiers private. Field types and nullability are not fully specified; handle the
        returned values without assuming fixed provider casts.
      security:
        - ApiToken: []
      parameters:
        - name: vehicle
          in: path
          required: true
          schema:
            type: integer
            examples:
              - 1001
      responses:
        "200":
          description: Response data. Examples use illustrative values.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Beacon"
        "401":
          description: Missing or invalid bearer credentials.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "403":
          description: The account is not permitted to view this vehicle.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "404":
          description: Vehicle not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
        "429":
          description: Request rate limit exceeded.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ApiError"
      x-codeSamples:
        - lang: Shell
          label: cURL · KATSANA V1
          source: |-
            curl --request GET 'https://api.katsana.com/vehicles/1001/beacon' \
              --header 'Accept: application/vnd.KATSANA.v1+json' \
              --header 'Time-Zone: Asia/Kuala_Lumpur' \
              --header "Authorization: Bearer $KATSANA_TOKEN"
        - lang: JavaScript
          label: Node.js · fetch
          source: |-
            const response = await fetch("https://api.katsana.com/vehicles/1001/beacon", {
              method: "GET",
              headers: {
                "Accept": "application/vnd.KATSANA.v1+json",
                "Time-Zone": "Asia/Kuala_Lumpur",
                "Authorization": `Bearer ${process.env.KATSANA_TOKEN}`
              },
            });
            if (!response.ok) throw new Error(`HTTP ${response.status}`);
            // Inspect the operation's response schema before parsing downloads or empty responses.
            console.log(await response.text());
components:
  securitySchemes:
    ApiToken:
      type: http
      scheme: bearer
      description: Paste the token returned by POST /auth. Enter only the token; the Bearer prefix is
        added automatically. Sign in with your account email and password to obtain it. Protected
        requests send it in the Authorization header. Account and resource permissions apply.
  schemas:
    ApiError:
      type: object
      properties:
        message:
          type: string
        errors: {}
        code: {}
        status_code:
          type: integer
      description: Dingo error fields vary by exception; absent fields are omitted.
    Beacon:
      type: object
      description: Tracker and SIM provider fields. These values can identify hardware or service access;
        keep actual values private. Nullability and provider casts remain permissive.
      properties:
        imei:
          description: Tracker IMEI. No actual identifier is included.
        product_code:
          description: Tracker product code.
        simcard_number:
          description: SIM card identifier/number. No actual SIM value is included.
        provider:
          description: Tracker/service provider value; its JSON type is not specified.
      example:
        imei: <device-imei>
        product_code: <product-code>
        simcard_number: <sim-number>
        provider: <provider>
    SubscriptionTransaction:
      type: object
      additionalProperties: true
      description: Transaction model returned after creating a renewal transaction and an external bill.
        The response is not a pay_url wrapper. Loaded relations, optional attributes and provider
        metadata may include fields beyond those listed.
      properties:
        id:
          type:
            - integer
            - string
          description: Created transaction identifier.
        status:
          type: integer
          description: Pending is 10 when the transaction is created.
        type:
          type: integer
          description: Renewal transaction type is 300.
        amount:
          type: integer
          description: Raw model amount cast to integer. Confirm monetary units and provider conversion before
            integration.
        user_id:
          type:
            - integer
            - string
          description: Authenticated account identifier.
        billplz_id:
          description: External bill identifier; keep actual values private.
        meta:
          type:
            - object
            - "null"
          additionalProperties: true
          description: Provider metadata including bill response. May contain payment links/access details; no
            captured values are included.
      example:
        id: 1001
        status: 10
        type: 300
        amount: 100
        user_id: 1001
        billplz_id: <bill-id>
        meta: {}
    SubscriptionDevice:
      type: object
      description: Current mapped device subscription-status row. The active controller explicitly sets
        subscription to null; the older full subscription/plan response is not used.
      properties:
        device_id:
          type:
            - integer
            - string
          description: Vehicle identifier.
        device_imei:
          description: Tracker identifier; keep actual values private.
        vehicle_number:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
        expired_at:
          type: string
          description: Device expiry formatted as YYYY-MM-DD HH:mm:ss.
        status:
          type: string
          enum:
            - N/A
            - Active
            - Expiring
            - Expired
            - Terminated
        subscription:
          type: "null"
          description: Explicitly null in the current controller; renewal detail is temporarily disabled.
        reseller:
          type: boolean
          description: Whether the vehicle has the reseller system tag.
      example:
        device_id: 1001
        device_imei: <device-imei>
        vehicle_number: EXAMPLE-1001
        description: Example vehicle
        expired_at: 2026-12-31 23:59:59
        status: Active
        subscription: null
        reseller: false
    PlaybackPreview:
      type: object
      description: Playback preview metadata. The url field contains the preview action object rather than
        a generated temporary URL; its serialized value is not specified.
      properties:
        id:
          description: Provider/database value; type and nullability are not specified.
        device_id:
          description: Provider/database value; type and nullability are not specified.
        user_id:
          description: Provider/database value; type and nullability are not specified.
        vacron_device_id:
          description: Provider/database value; type and nullability are not specified.
        duration:
          description: Provider/database value; type and nullability are not specified.
        time:
          description: Provider/database value; type and nullability are not specified.
        channel:
          description: Provider/database value; type and nullability are not specified.
        type:
          description: Provider/database value; type and nullability are not specified.
        status:
          description: Provider/database value; type and nullability are not specified.
        filename:
          description: Provider/database value; type and nullability are not specified.
        extension:
          description: Provider/database value; type and nullability are not specified.
        environment:
          description: Provider/database value; type and nullability are not specified.
        file_size:
          description: Provider/database value; type and nullability are not specified.
        created_at:
          description: Provider/database value; type and nullability are not specified.
        url:
          description: Assigned the preview action object, whose serialized value is not specified. Do not
            assume this is a usable URL. Treat any access-bearing link as private.
    VideoIndex:
      type: object
      properties:
        vehicles:
          type: array
          items:
            $ref: "#/components/schemas/VideoVehicle"
        datetime:
          description: Current server datetime. The format and timezone are not specified; check the returned
            value before parsing.
      example:
        vehicles: []
        datetime: 2026-01-15T08:30:00Z
    VideoVehicle:
      type: object
      description: Vehicle fields assembled for the MDVR product. Provider data, avatar and state
        representations can vary.
      properties:
        id:
          type:
            - integer
            - string
          description: Accessible vehicle identifier.
        plate_number:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
        avatar:
          description: Vehicle avatar value; shape depends on the model/provider.
        state:
          description: Current status value from the vehicle-status entity.
        dvr:
          $ref: "#/components/schemas/VideoDvr"
    VideoDvr:
      type: object
      properties:
        provider:
          description: MDVR provider identifier when supplied by the action.
        channels:
          description: Provider channel map or null. Channel entries can contain name and status.
        ratio:
          description: Provider-specific aspect ratio or null.
        liveStreamURL:
          type:
            - string
            - "null"
          description: Access-bearing provider link. Treat the complete URL as a credential. It can include a
            channel placeholder; no real URL is included.
        playback:
          type:
            - array
            - "null"
          items:
            $ref: "#/components/schemas/PlaybackRecord"
          description: Playback list on the playback index; absent on stream responses.
    PlaybackRecord:
      type: object
      description: Presented playback record from the list action. Provider/database casts remain permissive.
      properties:
        id:
          description: Provider/database value; its JSON type is not specified.
        device_id:
          description: Provider/database value; its JSON type is not specified.
        vacron_device_id:
          description: Provider/database value; its JSON type is not specified.
        user_id:
          description: Provider/database value; its JSON type is not specified.
        channel:
          description: Provider/database value; its JSON type is not specified.
        duration:
          description: Provider/database value; its JSON type is not specified.
        file_size:
          description: Provider/database value; its JSON type is not specified.
        filename:
          type: string
          description: Filename with extension, or an empty string.
        date:
          type: string
        start_time:
          type: string
        end_time:
          type: string
        status:
          type:
            - string
            - "null"
          description: Presented status such as downloaded, downloading, retrying or failed; unmatched
            provider states can be null.
    AssistanceShare:
      type: object
      description: Assistance share response. Nested vehicle data appears under vehicle.device; its
        complete field list is not specified. Share tokens and URLs grant private access.
      properties:
        id:
          type:
            - integer
            - string
          description: Created share identifier.
        vehicle:
          type: object
          properties:
            device:
              type: object
              additionalProperties: true
              description: Vehicle model data, including any loaded relations. Field availability and value types
                are not specified.
          additionalProperties: true
        user:
          $ref: "#/components/schemas/Profile"
        token:
          type: string
          description: Private share credential; never log or publish real values.
        url:
          type: string
          description: Private share link carrying the token. No real link is included.
        description:
          type:
            - string
            - "null"
        started_at:
          $ref: "#/components/schemas/LegacyDateTime"
        ended_at:
          $ref: "#/components/schemas/LegacyDateTime"
    LegacyDateTime:
      type:
        - string
        - "null"
      description: Legacy timestamp string, normally YYYY-MM-DD HH:mm:ss. Transformer output uses
        Time-Zone (UTC by default).
      examples:
        - 2026-01-15 08:30:00
    Profile:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        email:
          type:
            - string
            - "null"
        fullname:
          type:
            - string
            - "null"
        address:
          type:
            - string
            - "null"
        postcode:
          type:
            - string
            - "null"
        state:
          type:
            - string
            - "null"
        country:
          type:
            - string
            - "null"
        gender:
          type:
            - string
            - "null"
        phone_home:
          type:
            - string
            - "null"
        phone_mobile:
          type:
            - string
            - "null"
        tenant: {}
        meta:
          type: object
          properties:
            emergency:
              type: object
              properties:
                fullname:
                  type:
                    - string
                    - "null"
                phone: {}
        avatar:
          anyOf:
            - $ref: "#/components/schemas/Avatar"
            - type: "null"
        timezone:
          type:
            - string
            - "null"
        roles:
          type: array
          items:
            type: string
        permissions:
          type: array
          items:
            type: string
        created_at:
          $ref: "#/components/schemas/LegacyDateTime"
        updated_at:
          $ref: "#/components/schemas/LegacyDateTime"
        fleets:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
                examples:
                  - 1001
              name:
                type: string
              devices:
                type: integer
        plan:
          type: object
        company:
          type: object
        operations_subscription:
          type:
            - object
            - array
      example:
        id: 1001
        email: developer@example.com
        fullname: Example Developer
        timezone: UTC
        avatar: null
        roles: []
        permissions: []
    Avatar:
      type: object
      properties:
        url:
          type:
            - string
            - "null"
        thumb:
          type:
            - string
            - "null"
        marker:
          type:
            - string
            - "null"
    ValidationErrors:
      type: object
      additionalProperties:
        type: array
        items:
          type: string
      description: Field names map to validation messages. This differs from the Dingo exception envelope.
    FuelTypes:
      type: object
      properties:
        fuel_types:
          type: array
          items: {}
      description: Element validation is not defined by the current controller; configured values usually
        contain fuel-type names.
      example:
        fuel_types:
          - Diesel
    Report:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        message:
          type: string
        priority:
          type: integer
        latitude:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        longitude:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        pictures:
          type: array
          items:
            type: string
        created_at:
          $ref: "#/components/schemas/LegacyDateTime"
        updated_at:
          $ref: "#/components/schemas/LegacyDateTime"
    Fuel:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        user_id:
          type: integer
          examples:
            - 1001
        refuel_gauge:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        refuel_manual:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        price_litre:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        total_cost:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        fuel_type:
          type:
            - string
            - "null"
        odometer:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        distance:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        fuel_efficiency:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        fuel_efficiency_metric:
          type:
            - string
            - "null"
        latitude:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        longitude:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        notes:
          type:
            - string
            - "null"
        receipt:
          type:
            - string
            - "null"
        tracked_at:
          $ref: "#/components/schemas/LegacyDateTime"
        created_at:
          $ref: "#/components/schemas/LegacyDateTime"
        updated_at:
          $ref: "#/components/schemas/LegacyDateTime"
    Share:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        device_id:
          type: integer
          examples:
            - 1001
        user_id:
          type: integer
          examples:
            - 1001
        token:
          type: string
          description: Share credential; do not publish or log real values.
        url:
          type: string
          description: Private link carrying the share credential.
        description:
          type:
            - string
            - "null"
        active:
          type: boolean
        started_at:
          $ref: "#/components/schemas/LegacyDateTime"
        ended_at:
          $ref: "#/components/schemas/LegacyDateTime"
        deleted_at:
          $ref: "#/components/schemas/LegacyDateTime"
    TravelSummary:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        date:
          type: string
        number:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        start:
          type: object
          properties:
            id:
              type: integer
              examples:
                - 1001
            tracked_at:
              $ref: "#/components/schemas/LegacyDateTime"
        end:
          type: object
          properties:
            id:
              type: integer
              examples:
                - 1001
            tracked_at:
              $ref: "#/components/schemas/LegacyDateTime"
        distance:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        duration:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        idle_duration:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        max_speed:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        violation:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        score:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        type:
          type:
            - string
            - "null"
        drivemark: {}
        driver: {}
        odometer: {}
    Trip:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        start:
          $ref: "#/components/schemas/Ping"
        end:
          $ref: "#/components/schemas/Ping"
        distance:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        duration:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        max_speed:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        average_speed:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        idle_duration:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        score:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        idles:
          type: array
          items:
            $ref: "#/components/schemas/Ping"
        histories:
          type: array
          items:
            $ref: "#/components/schemas/Ping"
        violations:
          type: array
          items:
            type: object
        harsh:
          type: object
          properties:
            accelerate:
              type:
                - number
                - string
                - "null"
              description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
                Null means unavailable.
            braking:
              type:
                - number
                - string
                - "null"
              description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
                Null means unavailable.
            cornering:
              type:
                - number
                - string
                - "null"
              description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
                Null means unavailable.
        drivemark: {}
        type:
          type:
            - string
            - "null"
    Ping:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        latitude:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        longitude:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        tracked_at:
          $ref: "#/components/schemas/LegacyDateTime"
        speed:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        odometer:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        place: {}
        altitude:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        distance:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        course:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        fuel_percentage:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        ignition: {}
        temperature:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        voltage:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        connectivity:
          type: object
        driver: {}
        harsh: {}
        custom: {}
        battery-device:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        record: {}
        debug:
          type: object
      example:
        id: 1001
        latitude: 0
        longitude: 0
        tracked_at: 2026-01-15 08:30:00
    Travels:
      type: object
      properties:
        trips:
          type: array
          items:
            $ref: "#/components/schemas/Trip"
        summary:
          type: object
          properties:
            max_speed:
              type:
                - number
                - string
                - "null"
              description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
                Null means unavailable.
            distance:
              type:
                - number
                - string
                - "null"
              description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
                Null means unavailable.
            violation:
              type:
                - number
                - string
                - "null"
              description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
                Null means unavailable.
        duration:
          $ref: "#/components/schemas/Duration"
      required:
        - trips
        - summary
        - duration
    Duration:
      type: object
      properties:
        from:
          type: string
        to:
          type: string
      required:
        - from
        - to
      description: UTC duration bounds serialized as legacy date-time strings.
      example:
        from: 2026-01-15 00:00:00
        to: 2026-01-15 23:59:59
    TrackSummary:
      type: object
      properties:
        max_speed:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        average_speed:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        distance:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        violation:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
      example:
        max_speed: 0
        average_speed: 0
        distance: 0
        violation: 0
    DailySummary:
      type: object
      properties:
        date:
          type: string
        distance:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        duration:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        idle_duration:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        max_speed:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        trip:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        violation:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        score:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        drivemark: {}
        violations: {}
        costing: {}
      example:
        date: 2026-01-15
        distance: 0
        duration: 0
        idle_duration: 0
        max_speed: 0
        trip: 0
        violation: 0
        score: 100
    Positions:
      type: object
      properties:
        positions:
          type: array
          items:
            $ref: "#/components/schemas/Ping"
        duration:
          $ref: "#/components/schemas/Duration"
      required:
        - positions
        - duration
    Checkpoint:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        policy_id:
          type:
            - integer
            - "null"
        place_name:
          type:
            - string
            - "null"
        type:
          type:
            - string
            - "null"
        latitude:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        longitude:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        tracked_at:
          $ref: "#/components/schemas/LegacyDateTime"
    DriverEnvelope:
      type: object
      properties:
        driver:
          $ref: "#/components/schemas/Driver"
      required:
        - driver
    Driver:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        fullname:
          type:
            - string
            - "null"
        identification:
          type:
            - string
            - "null"
        identification_type:
          type:
            - string
            - "null"
        avatar:
          anyOf:
            - $ref: "#/components/schemas/Avatar"
            - type: "null"
        timezone:
          type:
            - string
            - "null"
        created_at:
          $ref: "#/components/schemas/LegacyDateTime"
        updated_at:
          $ref: "#/components/schemas/LegacyDateTime"
        fleet_id:
          type: integer
          examples:
            - 1001
        phone_mobile:
          type:
            - string
            - "null"
        email:
          type:
            - string
            - "null"
    VehicleList:
      type: object
      properties:
        devices:
          type: array
          items:
            $ref: "#/components/schemas/Vehicle"
        current_page:
          type: integer
        per_page:
          type: integer
        total:
          type: integer
        last_page:
          type: integer
        first_page_url:
          type:
            - string
            - "null"
        last_page_url:
          type:
            - string
            - "null"
        next_page_url:
          type:
            - string
            - "null"
        prev_page_url:
          type:
            - string
            - "null"
        path:
          type:
            - string
            - "null"
        from:
          type:
            - integer
            - "null"
        to:
          type:
            - integer
            - "null"
        links:
          type: array
          items:
            type: object
      required:
        - devices
      description: The resource array is always wrapped. Pagination metadata is added only when page is
        supplied.
    Vehicle:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        user_id:
          type: integer
          examples:
            - 1001
        imei:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
        product_code:
          type:
            - string
            - "null"
        vehicle_number:
          type:
            - string
            - "null"
        manufacturer:
          type:
            - string
            - "null"
        model:
          type:
            - string
            - "null"
        meta:
          type: object
          properties:
            today: {}
            latest:
              $ref: "#/components/schemas/Location"
            websocket:
              type: boolean
        mode:
          type:
            - string
            - "null"
        current:
          $ref: "#/components/schemas/Location"
        avatar:
          type:
            - string
            - "null"
        marker:
          type:
            - string
            - "null"
        today_max_speed:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        odometer:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        ends_at:
          $ref: "#/components/schemas/LegacyDateTime"
        timezone:
          type:
            - string
            - "null"
        profile:
          type: object
          description: Serialized vehicle profile; optional fields are not fully specified.
        plan:
          type: object
          properties:
            name: {}
            expiry_date: {}
            renewal_amount: {}
        fleets:
          type: array
          items:
            type: integer
            examples:
              - 1001
        tags:
          type: array
          items:
            type: string
        features:
          type: array
          items:
            type: string
        score:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        movement: {}
        temperature: {}
        online:
          type: boolean
        addons:
          type: array
          items:
            type: object
        regulation:
          type: object
        drivemark: {}
    Location:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        latitude:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        longitude:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        speed:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        state: {}
        ignition: {}
        voltage:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        battery:
          type:
            - number
            - string
            - "null"
          description: Numeric value; storage and provider casts may produce a JSON number or numeric string.
            Null means unavailable.
        gsm: {}
        tracked_at:
          type:
            - string
            - "null"
          description: Raw tracker timestamp. Check the returned format before parsing.
    DriverList:
      type: object
      properties:
        drivers:
          type: array
          items:
            $ref: "#/components/schemas/Driver"
        current_page:
          type: integer
        per_page:
          type: integer
        total:
          type: integer
        last_page:
          type: integer
        first_page_url:
          type:
            - string
            - "null"
        last_page_url:
          type:
            - string
            - "null"
        next_page_url:
          type:
            - string
            - "null"
        prev_page_url:
          type:
            - string
            - "null"
        path:
          type:
            - string
            - "null"
        from:
          type:
            - integer
            - "null"
        to:
          type:
            - integer
            - "null"
        links:
          type: array
          items:
            type: object
      required:
        - drivers
      description: The resource array is always wrapped. Pagination metadata is added only when page is
        supplied.
    FleetEnvelope:
      type: object
      properties:
        fleet:
          $ref: "#/components/schemas/Fleet"
      required:
        - fleet
    Fleet:
      type: object
      properties:
        id:
          type: integer
          examples:
            - 1001
        user_id:
          type: integer
          examples:
            - 1001
        name:
          type:
            - string
            - "null"
        description:
          type:
            - string
            - "null"
        timezone:
          type:
            - string
            - "null"
        managers:
          type: array
          items:
            type: object
            properties:
              id:
                type: integer
                examples:
                  - 1001
              email:
                type:
                  - string
                  - "null"
      example:
        id: 1001
        user_id: 1001
        name: Example fleet
        description: Example integration fleet
        timezone: Asia/Kuala_Lumpur
    FleetList:
      type: object
      properties:
        fleets:
          type: array
          items:
            $ref: "#/components/schemas/Fleet"
        current_page:
          type: integer
        per_page:
          type: integer
        total:
          type: integer
        last_page:
          type: integer
        first_page_url:
          type:
            - string
            - "null"
        last_page_url:
          type:
            - string
            - "null"
        next_page_url:
          type:
            - string
            - "null"
        prev_page_url:
          type:
            - string
            - "null"
        path:
          type:
            - string
            - "null"
        from:
          type:
            - integer
            - "null"
        to:
          type:
            - integer
            - "null"
        links:
          type: array
          items:
            type: object
      required:
        - fleets
      description: The resource array is always wrapped. Pagination metadata is added only when page is
        supplied.
    VehicleEnvelope:
      type: object
      properties:
        device:
          $ref: "#/components/schemas/Vehicle"
      required:
        - device
    JwtError:
      title: Sign-in error
      type: object
      properties:
        error:
          type: string
      required:
        - error
    JwtToken:
      title: API token
      type: object
      properties:
        token:
          type: string
          description: API token returned after sign-in. No real token is included in examples.
      required:
        - token
