openapi: 3.1.0
info:
  title: RobotPostal API
  description: |
    Physical mail delivery for AI agents. Send letters and postcards anywhere
    in the world from the US. Accepts payment via Stripe, x402, and MPP.

    ## Payment Methods

    ### x402 (recommended for agents)
    1. Send your order request without payment headers
    2. Receive a 402 response with payment details (wallet, amount, network)
    3. Pay the specified amount in USDC on Base
    4. Retry the same request with the `X-PAYMENT` header containing your proof

    ### MPP (Machine Payment Protocol)
    1. Send your order request with `X-PAYMENT-METHOD: mpp` header
    2. Receive a 402 challenge
    3. Complete the MPP payment flow
    4. Retry with payment proof

    ### Stripe
    Include `stripe_token` or `payment_method_id` in the order body.

    ## Pricing
    All prices are USPS retail rates + 20% markup. Use the /quote endpoint
    to get exact pricing before placing an order.
  version: 1.0.0
  contact:
    name: RobotPostal
    url: https://robotpostal.com

servers:
  - url: https://robotpostal.com/api/v1
    description: Production
  - url: http://localhost:3000/api/v1
    description: Local development

paths:
  /quote:
    post:
      operationId: getQuote
      summary: Get a price quote for sending mail
      description: Returns the postage cost, markup, and total for a given mail type and destination.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/QuoteRequest'
            examples:
              domestic_letter:
                summary: 3-page domestic letter
                value:
                  type: letter
                  pages: 3
                  destination: US
              international_postcard:
                summary: International postcard
                value:
                  type: postcard
                  destination: GB
      responses:
        '200':
          description: Price quote
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/QuoteResponse'
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /orders:
    post:
      operationId: createOrder
      summary: Create a mail order
      description: |
        Submit a mail order for delivery. Payment is required — see the API
        description for payment method details. Use the /quote endpoint first
        to check pricing.
      parameters:
        - name: X-PAYMENT
          in: header
          description: x402 payment proof (for x402 flow)
          schema:
            type: string
        - name: X-PAYMENT-METHOD
          in: header
          description: Payment method override (e.g., "mpp")
          schema:
            type: string
            enum: [mpp]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: Order created and paid
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '200':
          description: Duplicate order (idempotency key match)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '400':
          description: Invalid request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: Payment required — includes x402/MPP payment details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PaymentChallenge'

  /orders/{id}:
    get:
      operationId: getOrder
      summary: Get order status
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Order details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '404':
          description: Order not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'

  /orders/{id}/tracking:
    get:
      operationId: trackOrder
      summary: Track order progress with timeline and proof photos
      description: |
        Returns detailed tracking info including status progress bar,
        timeline of status changes, USPS tracking number (when available),
        and proof photos showing the mail being prepared and sent.
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      responses:
        '200':
          description: Order tracking details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrackingResponse'
        '404':
          description: Order not found

  /stats:
    get:
      operationId: getStats
      summary: Get live business financials (fully public)
      description: |
        All financials are public. Returns order counts, revenue,
        costs, net profit, and the investment roadmap showing where
        profits go. Updated in real-time from the database.
      responses:
        '200':
          description: Live business statistics
          content:
            application/json:
              schema:
                type: object
                properties:
                  orders:
                    type: object
                  financials:
                    type: object
                  costs:
                    type: object
                  investments:
                    type: array
                    items:
                      type: object

components:
  schemas:
    QuoteRequest:
      type: object
      required: [type, destination]
      properties:
        type:
          type: string
          enum: [letter, postcard]
        pages:
          type: integer
          minimum: 1
          maximum: 10
          description: Required for letters. Number of pages to print.
        destination:
          type: string
          minLength: 2
          maxLength: 2
          description: ISO 3166-1 alpha-2 country code. "US" for domestic.

    QuoteResponse:
      type: object
      properties:
        postageCents:
          type: integer
          description: USPS postage cost in cents
        markupCents:
          type: integer
          description: Service markup in cents (20%)
        totalCents:
          type: integer
          description: Total price in cents
        currency:
          type: string
          enum: [USD]

    Address:
      type: object
      required: [name, address1, city, country]
      properties:
        name:
          type: string
          maxLength: 200
        address1:
          type: string
          maxLength: 200
        address2:
          type: string
          maxLength: 200
        city:
          type: string
          maxLength: 100
        state:
          type: string
          maxLength: 100
        zip:
          type: string
          maxLength: 20
        country:
          type: string
          minLength: 2
          maxLength: 2

    CreateOrderRequest:
      type: object
      required: [type, content_format, from, to]
      properties:
        type:
          type: string
          enum: [letter, postcard]
        content_format:
          type: string
          enum: [plaintext, markdown, pdf]
        content_body:
          type: string
          maxLength: 100000
          description: Required for plaintext and markdown formats
        pages:
          type: integer
          minimum: 1
          maximum: 10
          description: Required for letters
        from:
          $ref: '#/components/schemas/Address'
        to:
          $ref: '#/components/schemas/Address'
        idempotency_key:
          type: string
          maxLength: 255
          description: Prevents duplicate orders
        stripe_token:
          type: string
          description: Stripe card token (for Stripe payment)
        payment_method_id:
          type: string
          description: Stripe PaymentMethod ID (for Stripe payment)

    Order:
      type: object
      properties:
        id:
          type: string
          format: uuid
        status:
          type: string
          enum: [received, paid, queued, printed, shipped]
        mailType:
          type: string
          enum: [letter, postcard]
        contentFormat:
          type: string
          enum: [plaintext, markdown, pdf]
        pages:
          type: integer
        postageCents:
          type: integer
        markupCents:
          type: integer
        totalCents:
          type: integer
        paymentMethod:
          type: string
          enum: [stripe, x402, mpp]
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time

    PaymentChallenge:
      type: object
      properties:
        error:
          type: string
          example: payment_required
        message:
          type: string
        x402:
          type: object
          properties:
            version:
              type: string
            accepts:
              type: array
              items:
                type: object
                properties:
                  scheme:
                    type: string
                  network:
                    type: string
                  price:
                    type: string
                  payTo:
                    type: string
            description:
              type: string
            facilitator:
              type: string

    TrackingResponse:
      type: object
      properties:
        order_id:
          type: string
          format: uuid
        status:
          type: string
          enum: [received, paid, queued, printed, shipped]
        mail_type:
          type: string
        destination:
          type: object
          properties:
            city:
              type: string
            country:
              type: string
        tracking:
          type: object
          nullable: true
          properties:
            number:
              type: string
            url:
              type: string
              format: uri
            carrier:
              type: string
        proof_photos:
          type: array
          items:
            type: string
            format: uri
          description: Public URLs of photos showing the mail being prepared/sent
        progress:
          type: object
          properties:
            steps:
              type: array
              items:
                type: object
                properties:
                  name:
                    type: string
                  completed:
                    type: boolean
                  current:
                    type: boolean
            percent:
              type: integer
        timeline:
          type: array
          items:
            type: object
            properties:
              status:
                type: string
              note:
                type: string
              proof_photo:
                type: string
                format: uri
              timestamp:
                type: string
                format: date-time

    Error:
      type: object
      properties:
        error:
          type: string
        message:
          type: string
        details:
          type: array
          items:
            type: object
