openapi: 3.1.0
info:
  title: Delivery Status
  version: 0.1.0
  summary: Package tracking connector for the Muse directory
  description: |
    Product: Delivery Status (https://www.deliverystatus.now).
    Muse-facing copy: “Check with Delivery Status?”
    The connector tracks via tracking data providers when a live aggregator
    key is configured; otherwise an in-process mock.
    Freemium single track is public. Live track responses are cached ~30 minutes
    per tracking_number (+ optional carrier). MSHIP-* demo codes always use mock.
    Watch-list auth routes exist but are not featured on the marketing site.
    Shipment insurance is future / not offered yet — POST /v1/checkout/insure
    is an inert placeholder and is not linked from the site.
    Not a merchant Fast/Bolt checkout.
    Product display name comes from PRODUCT_DISPLAY_NAME / src/lib/brand.ts.
  contact:
    name: Brig / octograb
    url: https://www.deliverystatus.now
  license:
    name: UNLICENSED
servers:
  - url: https://www.deliverystatus.now
    description: Production (prefer www)
  - url: /
    description: Same origin as the Next.js host
paths:
  /v1/health:
    get:
      operationId: health
      summary: Liveness and tracking mode (live or demo)
      responses:
        "200":
          description: Service is up
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Health"
  /v1/track:
    post:
      operationId: trackPackage
      summary: Free single-package track
      description: |
        Returns normalized status, ETA, and events. MSHIP-* codes always use the
        mock provider. Live aggregator responses are cached ~30 minutes for the
        same tracking_number (+ optional carrier).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TrackRequest"
      responses:
        "200":
          description: Normalized tracking
          content:
            application/json:
              schema:
                type: object
                required: [tracking]
                properties:
                  tracking:
                    $ref: "#/components/schemas/NormalizedTracking"
        "400":
          $ref: "#/components/responses/Error"
        "502":
          $ref: "#/components/responses/Error"
  /v1/packages:
    get:
      operationId: listWatches
      summary: List the caller’s watch list
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Watches
          content:
            application/json:
              schema:
                type: object
                required: [watches]
                properties:
                  watches:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
        "401":
          $ref: "#/components/responses/Error"
        "503":
          $ref: "#/components/responses/Error"
  /v1/packages/watch:
    post:
      operationId: watchPackage
      summary: Persist a watch (auth; billing not enforced in v1)
      security:
        - bearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TrackRequest"
      responses:
        "201":
          description: Watch created or refreshed
        "401":
          $ref: "#/components/responses/Error"
        "503":
          $ref: "#/components/responses/Error"
  /v1/checkout/insure:
    post:
      operationId: insureCheckout
      summary: Insurance checkout placeholder (not offered yet)
      description: |
        Future / not offered yet. Always returns checkout_url null. Not linked
        from the Delivery Status marketing site.
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                tracking_number:
                  type: string
                coverage_cents:
                  type: integer
                  minimum: 1
      responses:
        "200":
          description: Placeholder only — insurance not offered yet; checkout_url is null
          content:
            application/json:
              schema:
                type: object
                required: [checkout]
                properties:
                  checkout:
                    $ref: "#/components/schemas/InsuranceCheckoutStub"
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Auth access token for project muse-ship (wlihrxvofxwzrnyvxooh)
  responses:
    Error:
      description: Error envelope
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
  schemas:
    Health:
      type: object
      required: [ok, service, product, tracking]
      properties:
        ok:
          type: boolean
        service:
          type: string
          const: delivery-status
        product:
          type: string
          example: Delivery Status
          description: Display name from getProductDisplayName() (default Delivery Status).
        tracking:
          type: string
          enum: [live, demo]
          description: live when a live aggregator key is configured; demo when mock.
    TrackRequest:
      type: object
      required: [tracking_number]
      properties:
        tracking_number:
          type: string
          minLength: 4
          maxLength: 100
        carrier:
          type: string
          description: Optional courier hint. Omit for live-network auto-detect.
    PackageStatus:
      type: string
      enum:
        - pending
        - info_received
        - in_transit
        - out_for_delivery
        - attempt_failed
        - delivered
        - available_for_pickup
        - exception
        - expired
        - unknown
    TrackingEvent:
      type: object
      required: [occurred_at, status, message, location]
      properties:
        occurred_at:
          type: [string, "null"]
        status:
          $ref: "#/components/schemas/PackageStatus"
        message:
          type: [string, "null"]
        location:
          type: [string, "null"]
    NormalizedTracking:
      type: object
      required: [tracking_number, carrier, status, eta, events, provider]
      properties:
        tracking_number:
          type: string
        carrier:
          type: [string, "null"]
        status:
          $ref: "#/components/schemas/PackageStatus"
        eta:
          type: [string, "null"]
        events:
          type: array
          items:
            $ref: "#/components/schemas/TrackingEvent"
        provider:
          type: string
          description: Internal tracking source id (demo is mock; live sources vary by host config).
    InsuranceCheckoutStub:
      type: object
      description: Inert placeholder — shipment insurance is not offered yet.
      required: [provider, status, live, checkout_url, offer, next_step]
      properties:
        provider:
          type: string
          description: Placeholder payment provider id (wire format; not a live checkout).
        status:
          const: placeholder
        live:
          const: false
        checkout_url:
          type: "null"
        offer:
          type: object
          required: [tracking_number, coverage_cents, premium_cents, currency]
          properties:
            tracking_number:
              type: [string, "null"]
            coverage_cents:
              type: integer
            premium_cents:
              type: integer
            currency:
              const: usd
        next_step:
          type: string
    Error:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
            message:
              type: string
