openapi: 3.1.0
info:
  title: In-Transit Visibility API
  version: 1.0.0-public-preview
  contact:
    name: DSDC APIs Full Truckload
    url: https://github.com/dsdcapis/full-truckload
  license:
    name: DSDC Repository License
    url: https://github.com/dsdcapis/full-truckload/blob/main/LICENSE.md
  description: |
    # Overview
    In-Transit Visibility is the capability to track freight movements through milestones, events and 
    location updates in real time, from pickup to delivery. It is vital to the lifecycle of a load because
    it provides insight into where a shipment is at each stage and alerts all parties of important
    milestones or issues. This capability ties into the broader Digital Standards Development
    Council open API standards initiative, which aims to digitize data exchange in freight
    transportation. By adopting standard APIs, the industry can reduce manual processes, improve
    data accuracy, increase visibility into shipments, enable real-time notifications of shipment
    changes, and drive process automation.

    Shippers today continue to demand real-time updates at every key milestone - before pickup,
    during transit, and upon arrival. In response, industry leaders are making automated digital
    tracking a core part of operations, replacing phone calls and emails with API-based status
    sharing. This broad industry trend underscores how critical in-transit visibility has become. It
    also reinforces the NMFTA's mission to standardize visibility.

    By implementing this API, all parties - shippers, carriers, and intermediaries - share a single
    source of truth about a load's status. In-transit updates, when combined with other NMFTA
    standard APIs (e.g. electronic tendering and eBOL), form a continuous digital thread from load
    creation to completion, greatly enhancing transparency and efficiency in freight movements.    
    # Value Proposition

    ## Shipper

    Gaining in-transit visibility allows shippers to easily get updates on the status and location of their shipments, reducing misunderstandings, human error, and theft. For example, instead of waiting for manual updates, a shipper can see when a load is picked up, in transit, or delayed, and even receive location updates before pickup occurs. This proactive insight gives shippers peace of mind and the ability to address exceptions quickly.

    ## Carrier

    The In-Transit Visibility API allows carriers to provide digital status updates to relevant parties using a standard protocol. This approach enables tracking information to be shared with shippers and third-party logistics providers (3PLs), supporting automated communication of updates such as departure, arrival, or delay notifications, and contributing to operational transparency.

    ## 3rd Party

    The In-Transit Visibility API will allow third parties of all kinds to receive and send necessary shipment information to ensure a seamless flow through the life cycle of a shipment. Due to the nature of their business and having to interact with multiple parties in the transportation industry, they stand much to gain by simplification of their business processes, which the In-Transit Visibility specification will enable. Overall, the In-Transit Visibility standard helps 3rd parties coordinate more effectively and provide better service with less overhead.

    # Capabilities:

    - Pull events: GET /v1/events (page-based, deterministic ordering)
    - Webhook delivery: webhooks/shipmentEvents (EventBatch + HMAC)
    - Subscription management: /v1/subscriptions
    - Pagination strategy: Page-Based method with page/pageSize
    - Standardized event types
    - Ordering, idempotency, retries
    - [RFC 7807 Problem Details](https://datatracker.ietf.org/doc/html/rfc7807)

    # Product Requirements Document (PRD)

    The Product Requirements Document (PRD) for this API can be found [here](https://dsdcapis.github.io/full-truckload/api-prds/API%20Product%20Requirements%20-%20In%20Transit%20Visibility.pdf).
tags:
  - name: Events
    description: Pull shipment events
  - name: Subscriptions
    description: Manage webhook subscriptions
paths:
  /v1/events:
    get:
      tags:
        - Events
      summary: List shipment events (page-based)
      operationId: listEvents
      description: |
        Returns a page of events. Pagination in headers; body uses EventsPage for consistency.
        Results are deterministically ordered by `shipmentId`, `sequence`, `id`.      
      parameters:
        - in: query
          name: shipmentId
          schema:
            type: string
          description: Filter by canonical shipment id.
        - in: query
          name: eventTypes
          schema:
            type: array
            items:
              $ref: '#/components/schemas/EventType'
          description: One or more event types.
        - in: query
          name: occurredFrom
          schema:
            type: string
            format: date-time
          description: occurredAt >= this timestamp.
        - in: query
          name: occurredTo
          schema:
            type: string
            format: date-time
          description: occurredAt < this timestamp.
        - in: query
          name: page
          schema:
            type: integer
            minimum: 1
            default: 1
          description: 1-based page index.
        - in: query
          name: pageSize
          schema:
            type: integer
            minimum: 1
            maximum: 500
            default: 100
          description: Results per page.
        - in: query
          name: order
          schema:
            type: string
            enum:
              - asc
              - desc
            default: asc
          description: Sort direction on `shipmentId`, `sequence`, `id`.
      responses:
        '200':
          description: A page of events
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/EventsPage'
        default:
          $ref: '#/components/responses/UnexpectedError'
  /v1/subscriptions:
    get:
      tags:
        - Subscriptions
      summary: List subscriptions
      operationId: listSubscriptions
      description: |
        Returns a page of subscriptions. Pagination in headers; body uses SubscriptionsPage for consistency.
        Results are deterministically ordered by `id`.      
      parameters:
        - in: query
          name: status
          schema:
            type: string
            enum:
              - active
              - paused
              - inactive
            default: active
        - in: query
          name: page
          schema:
            type: integer
            minimum: 1
            default: 1
        - in: query
          name: pageSize
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        '200':
          description: Subscriptions page
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SubscriptionsPage'
        default:
          $ref: '#/components/responses/UnexpectedError'
    post:
      tags:
        - Subscriptions
      summary: Create a subscription
      operationId: createSubscription
      description: |
        Create a subscription to receive in-transit events via webhook. 
        Provide the delivery configuration webhook url and hmac_secret_id  and filters event_types and shipment IDs. 
        Returns the created Subscription on success.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SubscriptionCreate'
      responses:
        '201':
          description: Created
          headers:
            Location:
              $ref: '#/components/headers/Location'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Subscription'
        default:
          $ref: '#/components/responses/UnexpectedError'
  /v1/subscriptions/{subscriptionId}:
    get:
      tags:
        - Subscriptions
      summary: Get a subscription
      operationId: getSubscription
      description: |
        Retrieve a single subscription by its unique ID.
        Returns the subscription's current configuration and status.
      parameters:
        - in: path
          name: subscriptionId
          required: true
          schema:
            type: string
      responses:
        '200':
          description: The subscription that matches the provided subscription ID.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Subscription'
        default:
          $ref: '#/components/responses/UnexpectedError'
    patch:
      tags:
        - Subscriptions
      summary: Update a subscription (merge-patch)
      operationId: updateSubscription
      description: Partial update using [JSON Merge Patch](https://datatracker.ietf.org/doc/html/rfc7386). Provide only fields you want to change.
      parameters:
        - in: path
          name: subscriptionId
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/merge-patch+json:
            schema:
              $ref: '#/components/schemas/SubscriptionPatch'
      responses:
        '200':
          description: Updated subscription
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Subscription'
        default:
          $ref: '#/components/responses/UnexpectedError'
    delete:
      tags:
        - Subscriptions
      summary: Delete a subscription
      operationId: deleteSubscription
      description: Delete a subscription by its unique ID. Stops future deliveries and removes the subscription.
      parameters:
        - in: path
          name: subscriptionId
          required: true
          schema:
            type: string
      responses:
        '204':
          description: Deleted
        default:
          $ref: '#/components/responses/UnexpectedError'
webhooks:
  shipmentEvents:
    post:
      summary: Shipment events webhook (from Carrier -> Subscriber)
      description: |
        We POST batches of events to your configured `endpointUrl`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EventBatch'
      responses:
        '200':
          description: Acknowledged (no retry)
        '202':
          description: Accepted (no retry)
        default:
          $ref: '#/components/responses/UnexpectedError'
components:
  schemas:
    EventType:
      title: Event Type
      type: string
      description: Normalized event taxonomy across modes.
      enum:
        - PICKUP_SCHEDULED
        - PICKUP_ATTEMPTED
        - PICKED_UP
        - ARRIVED_AT_TERMINAL
        - DEPARTED_TERMINAL
        - IN_TRANSIT
        - DELAY
        - EXCEPTION
        - CUSTOMS_HOLD
        - CUSTOMS_CLEARED
        - OUT_FOR_DELIVERY
        - DELIVERY_ATTEMPTED
        - DELIVERED
        - PROOF_OF_DELIVERY
        - CANCELLED
        - GATE_IN
        - GATE_OUT
        - VESSEL_LOADED
        - VESSEL_UNLOADED
        - RAIL_ARRIVAL
        - RAIL_DEPARTURE
        - AIR_DEPARTURE
        - AIR_ARRIVAL
        - OTHER
      default: OTHER
    ErrorDetail:
      type: object
      description: An object to provide explicit details on a problem towards an API consumer.
      properties:
        detail:
          type: string
          description: A granular description on the specific error related to a body property, query parameter, path parameters, and/or header.
          maxLength: 4096
        pointer:
          type: string
          description: A JSON Pointer to a specific request body property that is the source of error.
          maxLength: 1024
        parameter:
          type: string
          description: The name of the query or path parameter that is the source of error.
          maxLength: 1024
        header:
          type: string
          description: The name of the header that is the source of error.
          maxLength: 1024
        code:
          type: string
          description: A string containing additional provider specific codes to identify the error context.
          maxLength: 50
      required:
        - detail
    Errors:
      type: array
      description: An array of error details to accompany a problem details response.
      maxItems: 1000
      items:
        $ref: '#/components/schemas/ErrorDetail'
    ProblemDetails:
      type: object
      properties:
        type:
          type: string
          description: A URI reference that identifies the problem type.
          format: uri
          maxLength: 1024
        status:
          type: integer
          description: The HTTP status code generated by the origin server for this occurrence of the problem.
          format: int32
          minimum: 100
          maximum: 599
        title:
          type: string
          description: A short, human-readable summary of the problem type. It should not change from occurrence to occurrence of the problem, except for purposes of localization.
          maxLength: 1024
        detail:
          type: string
          description: A human-readable explanation specific to this occurrence of the problem.
          maxLength: 4096
        instance:
          type: string
          description: A URI reference that identifies the specific occurrence of the problem. It may or may not yield further information if dereferenced.
          maxLength: 1024
        code:
          type: string
          description: An API specific error code aiding the provider team understand the error based on their own potential taxonomy or registry.
          maxLength: 50
        errors:
          $ref: '#/components/schemas/Errors'
      required:
        - title
    ProblemDetails-2:
      title: Problem Details
      allOf:
        - $ref: '#/components/schemas/ProblemDetails'
    Location:
      title: Location
      type: object
      properties:
        locationId:
          type: string
          description: Unique location ID.
        name:
          type: string
        type:
          type: string
          enum:
            - FACILITY
            - CITY
            - GEOPOINT
          default: GEOPOINT
        latitude:
          type: number
          minimum: -90
          maximum: 90
        longitude:
          type: number
          minimum: -180
          maximum: 180
        city:
          type: string
        state:
          type: string
        postalCode:
          type: string
        country:
          type: string
          minLength: 3
          maxLength: 3
          description: ISO 3166-1 alpha-3
        address1:
          type: string
        address2:
          type: string
    TransportationMode:
      title: Transportation Mode
      type: string
      enum:
        - FTL
        - LTL
        - PARCEL
        - OCEAN
        - AIR
        - RAIL
        - INTERMODAL
        - OTHER
      default: OTHER
    Shipment:
      title: Shipment
      type: object
      properties:
        shipmentId:
          type: string
          description: Unique shipment identifier.
        mode:
          $ref: '#/components/schemas/TransportationMode'
        scac:
          type: string
          description: Standard Carrier Alpha Code (if applicable).
        references:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
              value:
                type: string
        requestedPickupDate:
          type: string
          format: date-time
        startDate:
          type: string
          format: date-time
        endDate:
          type: string
          format: date-time
        origin:
          $ref: '#/components/schemas/Location'
        destination:
          $ref: '#/components/schemas/Location'
      required:
        - shipmentId
        - origin
        - destination
    Event:
      title: Event
      type: object
      description: Standardized shipment event
      properties:
        eventId:
          type: string
          description: Event id (UUID or ULID)
        type:
          $ref: '#/components/schemas/EventType'
        status:
          type: string
          description: Optional carrier-native status code or text.
        occurredAt:
          type: string
          format: date-time
          description: When the event happened (source-of-truth time).
        reportedAt:
          type: string
          format: date-time
          description: When the event was recorded in your system.
        sequence:
          type: integer
          minimum: 0
          description: Per-shipment monotonically increasing sequence for ordering.
        location:
          $ref: '#/components/schemas/Location'
        notes:
          type: string
        attributes:
          type: object
          additionalProperties: true
          description: Extensible key/value metadata (e.g., terminalCode, reasonCode).
        documents:
          type: array
          items:
            type: object
            properties:
              type:
                type: string
                enum:
                  - POD
                  - BOL
                  - INVOICE
                  - LABEL
                  - OTHER
                default: OTHER
              url:
                type: string
                format: uri
              mimeType:
                type: string
        shipment:
          $ref: '#/components/schemas/Shipment'
      required:
        - eventId
        - shipment
        - type
        - occurredAt
        - sequence
    EventsPage:
      title: Events Page
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Event'
        page:
          type: integer
          minimum: 1
        pageSize:
          type: integer
        totalPages:
          type: integer
          description: Total number of pages if known (may be null for performance).
        totalCount:
          type: integer
          description: Total number of items if known (may be null for performance).
      required:
        - data
        - page
        - pageSize
    DeliveryMetadata:
      title: Delivery Metadata
      type: object
      properties:
        maxAttempts:
          type: integer
          minimum: 1
          default: 12
          description: Total number of retry attempts before giving up
        initialBackoffSeconds:
          type: integer
          minimum: 1
          default: 5
          description: Delay before first retry
        maxBackoffSeconds:
          type: integer
          minimum: 1
          default: 3600
          description: Maximum delay between retries
        batchMaxSize:
          type: integer
          minimum: 1
          maximum: 1000
          default: 200
          description: Max events per webhook POST
        rateLimitPerMinute:
          type: integer
          minimum: 1
          default: 600
          description: Max deliveries per minute
    SubscriptionBase:
      title: Subscription Base
      type: object
      properties:
        endpointUrl:
          type: string
          format: uri
        hmacSecretId:
          type: string
          description: Reference to the stored secret used for HMAC signing.
        filters:
          type: object
          properties:
            eventTypes:
              type: array
              items:
                $ref: '#/components/schemas/EventType'
            shipmentIds:
              type: array
              items:
                type: string
          additionalProperties: false
        delivery:
          $ref: '#/components/schemas/DeliveryMetadata'
    Subscription:
      title: Subscription
      allOf:
        - $ref: '#/components/schemas/SubscriptionBase'
        - type: object
          properties:
            id:
              type: string
            createdAt:
              type: string
              format: date-time
            updatedAt:
              type: string
              format: date-time
            status:
              type: string
              enum:
                - active
                - paused
                - inactive
              default: active
          required:
            - id
            - createdAt
            - updatedAt
            - status
            - endpointUrl
      unevaluatedProperties: false
    SubscriptionsPage:
      title: Subscriptions Page
      type: object
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Subscription'
        page:
          type: integer
        pageSize:
          type: integer
        totalPages:
          type: integer
        totalCount:
          type: integer
      required:
        - data
        - page
        - pageSize
    SubscriptionCreate:
      title: Subscription Create
      allOf:
        - $ref: '#/components/schemas/SubscriptionBase'
        - type: object
          required:
            - endpointUrl
            - hmacSecretId
      unevaluatedProperties: false
    SubscriptionPatch:
      title: Subscription Patch
      allOf:
        - $ref: '#/components/schemas/SubscriptionBase'
        - type: object
          properties:
            status:
              type: string
              enum:
                - active
                - paused
                - inactive
              default: active
      unevaluatedProperties: false
    EventBatch:
      title: Event Batch
      type: object
      description: Batch delivery of events for webhook posts.
      properties:
        deliveryId:
          type: string
          description: Stable id for this delivery (constant across retries).
        sentAt:
          type: string
          format: date-time
          description: When the batch was sent by the publisher.
        events:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/Event'
      required:
        - deliveryId
        - sentAt
        - events
  responses:
    UnexpectedError:
      description: Unexpected error
      content:
        application/problem+json:
          schema:
            $ref: '#/components/schemas/ProblemDetails-2'
  headers:
    Location:
      description: |
        Refers to a specific resource in relation to the response. The type of
        relationship is defined by the combination of request method and status code
        semantics. See [RFC 7231, Section 7.1.2](https://tools.ietf.org/html/rfc7231#section-7.1.2).
      schema:
        type: string
        format: uri
