openapi: 3.1.0
info:
  title: SAAVI API
  version: 1.0.0
  description: "SAAVI API — buyer-facing API for enterprise buyers submitting purchase orders to a supplier tenant."
servers:
- url: https://api.saavi.com.au/api/supplier/v1
  description: "Production"
security:
- clientCredentials: []
tags:
- name: Auth
- name: PurchaseOrders
- name: Catalog
- name: Pricing
- name: Availability
- name: Shipments
- name: Invoices
- name: POD
- name: Webhooks
- name: Deferred
paths:
  /oauth/token:
    post:
      tags:
      - Auth
      security: []
      summary: Issue access token (client credentials)
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/TokenRequest'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenResponse'
        '401':
          $ref: '#/components/responses/Error'
      x-mojo-status: future_activation_gated
  /purchase-orders/validate:
    post:
      tags:
      - PurchaseOrders
      summary: Validate a PO without staging
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PurchaseOrderSubmit'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationResponse'
        '400':
          $ref: '#/components/responses/Error'
        '401':
          $ref: '#/components/responses/Error'
        '403':
          $ref: '#/components/responses/Error'
      x-mojo-status: future_activation_gated
  /purchase-orders:
    post:
      tags:
      - PurchaseOrders
      summary: Submit a PO
      parameters:
      - $ref: '#/components/parameters/IdempotencyKey'
      - $ref: '#/components/parameters/CorrelationId'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PurchaseOrderSubmit'
      responses:
        '202':
          description: Accepted for intake
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PurchaseOrderSubmitResponse'
        '400':
          $ref: '#/components/responses/Error'
        '409':
          $ref: '#/components/responses/Error'
      x-mojo-status: future_activation_gated
    get:
      tags:
      - PurchaseOrders
      summary: Lookup POs by buyer PO number
      parameters:
      - in: query
        name: buyerPoNumber
        required: true
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/PurchaseOrderStatus'
      x-mojo-status: future_activation_gated
  /purchase-orders/{supplierPoId}:
    get:
      tags:
      - PurchaseOrders
      parameters:
      - $ref: '#/components/parameters/SupplierPoId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PurchaseOrderStatus'
        '404':
          $ref: '#/components/responses/Error'
      x-mojo-status: future_activation_gated
  /purchase-orders/{supplierPoId}/acknowledgement:
    get:
      tags:
      - PurchaseOrders
      parameters:
      - $ref: '#/components/parameters/SupplierPoId'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Acknowledgement'
      x-mojo-status: future_activation_gated
  /purchase-orders/{supplierPoId}/events:
    get:
      tags:
      - PurchaseOrders
      parameters:
      - $ref: '#/components/parameters/SupplierPoId'
      responses:
        '200':
          description: Buyer-safe event timeline
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/BuyerEvent'
      x-mojo-status: future_activation_gated
  /catalog:
    get:
      tags:
      - Catalog
      parameters:
      - in: query
        name: page
        schema:
          type: integer
          default: 1
      - in: query
        name: limit
        schema:
          type: integer
          default: 100
          maximum: 500
      - in: query
        name: updatedSince
        schema:
          type: string
          format: date-time
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/CatalogItem'
      x-mojo-status: future_activation_gated
  /catalog/{sku}:
    get:
      tags:
      - Catalog
      parameters:
      - in: path
        name: sku
        required: true
        schema:
          type: string
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CatalogItem'
      x-mojo-status: future_activation_gated
  /pricing:
    get:
      tags:
      - Pricing
      parameters:
      - in: query
        name: sku
        required: true
        schema:
          type: string
      - in: query
        name: quantity
        schema:
          type: number
      - in: query
        name: uom
        schema:
          type: string
      - in: query
        name: shipTo
        schema:
          type: string
      - in: query
        name: requestedDeliveryDate
        schema:
          type: string
          format: date
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PricingItem'
      x-mojo-status: future_activation_gated
  /availability:
    get:
      tags:
      - Availability
      parameters:
      - in: query
        name: sku
        required: true
        schema:
          type: string
      - in: query
        name: uom
        schema:
          type: string
      responses:
        '200':
          description: OK (banded by default)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AvailabilityResponse'
      x-mojo-status: future_activation_gated
  /shipments:
    get:
      tags:
      - Shipments
      responses:
        '200':
          $ref: '#/components/responses/NotAvailableYet'
      x-mojo-status: future_activation_gated
  /invoices:
    get:
      tags:
      - Invoices
      responses:
        '200':
          $ref: '#/components/responses/NotAvailableYet'
      x-mojo-status: future_activation_gated
  /pod:
    get:
      tags:
      - POD
      responses:
        '200':
          $ref: '#/components/responses/NotAvailableYet'
      x-mojo-status: future_activation_gated
  /webhooks:
    post:
      tags:
      - Webhooks
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/WebhookEndpointCreate'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/WebhookEndpointCreated'
      x-mojo-status: future_activation_gated
    get:
      tags:
      - Webhooks
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/WebhookEndpoint'
      x-mojo-status: future_activation_gated
  /webhooks/{id}:
    delete:
      tags:
      - Webhooks
      parameters:
      - in: path
        name: id
        required: true
        schema:
          type: string
      responses:
        '204':
          description: Deleted
      x-mojo-status: future_activation_gated
  /webhooks/{id}/test:
    post:
      tags:
      - Webhooks
      parameters:
      - in: path
        name: id
        required: true
        schema:
          type: string
      responses:
        '202':
          description: Test enqueued
      x-mojo-status: future_activation_gated
  /purchase-orders/cxml:
    post:
      tags:
      - Deferred
      summary: "cXML PO \u2014 deferred"
      responses:
        '501':
          $ref: '#/components/responses/NotImplemented'
      x-mojo-status: future_activation_gated
  /purchase-orders/edi:
    post:
      tags:
      - Deferred
      summary: "EDI 850 \u2014 deferred"
      responses:
        '501':
          $ref: '#/components/responses/NotImplemented'
      x-mojo-status: future_activation_gated
  /internal/orderflow/supplier-intake:
    post:
      tags:
      - Deferred
      summary: "OrderFlow supplier intake"
      x-mojo-status: available
      description: Service-to-service endpoint used by OrderFlow. Dry-run only. Never
        invokes writers.
      responses:
        '200':
          description: accepted_for_processing
        '401':
          description: auth_failed
        '409':
          description: idempotency_conflict
        '422':
          description: validation error
components:
  parameters:
    IdempotencyKey:
      in: header
      name: Idempotency-Key
      required: true
      schema:
        type: string
        maxLength: 128
    CorrelationId:
      in: header
      name: X-Correlation-Id
      required: false
      schema:
        type: string
        maxLength: 128
    SupplierPoId:
      in: path
      name: supplierPoId
      required: true
      schema:
        type: string
        format: uuid
  securitySchemes:
    clientCredentials:
      type: oauth2
      flows:
        clientCredentials:
          tokenUrl: /oauth/token
          scopes:
            supplier.orders.write: Submit and validate POs
            supplier.orders.read: Read PO status and events
            supplier.catalog.read: Read catalogue
            supplier.pricing.read: Read pricing
            supplier.availability.read: Read availability
            supplier.shipments.read: Read shipments (stub)
            supplier.invoices.read: Read invoices (stub)
            supplier.pod.read: Read POD (stub)
            supplier.webhooks.manage: Manage webhook endpoints
  responses:
    Error:
      description: Error
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotAvailableYet:
      description: Endpoint surface present but backing data not available yet
      content:
        application/json:
          schema:
            type: object
            properties:
              status:
                type: string
                enum:
                - not_available_yet
              reason:
                type: string
    NotImplemented:
      description: Deferred; behind experimental flag
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  schemas:
    TokenRequest:
      type: object
      required:
      - grant_type
      - client_id
      - client_secret
      properties:
        grant_type:
          type: string
          enum:
          - client_credentials
        client_id:
          type: string
        client_secret:
          type: string
        scope:
          type: string
    TokenResponse:
      type: object
      properties:
        access_token:
          type: string
        token_type:
          type: string
          enum:
          - Bearer
        expires_in:
          type: integer
        scope:
          type: string
    PurchaseOrderLineSubmit:
      type: object
      required:
      - lineNumber
      - buyerSku
      - quantity
      - uom
      properties:
        lineNumber:
          type: integer
        buyerSku:
          type: string
        quantity:
          type: number
        uom:
          type: string
        unitPrice:
          type: number
        currency:
          type: string
        requestedDeliveryDate:
          type: string
          format: date
        shipToLocationCode:
          type: string
        notes:
          type: string
    PurchaseOrderSubmit:
      type: object
      required:
      - buyerPoNumber
      - environment
      - lines
      properties:
        buyerPoNumber:
          type: string
        environment:
          type: string
          enum:
          - sandbox
          - production
        requestedDeliveryDate:
          type: string
          format: date
        shipToLocationCode:
          type: string
        currency:
          type: string
        notes:
          type: string
        lines:
          type: array
          items:
            $ref: '#/components/schemas/PurchaseOrderLineSubmit'
    ValidationCheck:
      type: object
      properties:
        code:
          type: string
        severity:
          type: string
          enum:
          - info
          - warn
          - error
        path:
          type: string
        message:
          type: string
    ValidationResponse:
      type: object
      properties:
        validation_result_id:
          type: string
          format: uuid
        overall:
          type: string
          enum:
          - pass
          - warn
          - fail
        checks:
          type: array
          items:
            $ref: '#/components/schemas/ValidationCheck'
        warnings:
          type: array
          items:
            type: string
        correlation_id:
          type: string
    PurchaseOrderSubmitResponse:
      type: object
      properties:
        supplier_po_id:
          type: string
          format: uuid
        buyer_po_number:
          type: string
        status:
          type: string
          enum:
          - received
          - accepted
          - pending_supplier_review
          - rejected
        acknowledgement_id:
          type: string
        correlation_id:
          type: string
        submitted_to_supplier_system:
          type: boolean
        supplier_system_status:
          type: string
          enum:
          - pending
          - submitted
          - confirmed
          - rejected
          - failed
        estimated_next_status:
          type: string
        warnings:
          type: array
          items:
            type: string
    PurchaseOrderStatus:
      type: object
      properties:
        supplier_po_id:
          type: string
          format: uuid
        buyer_po_number:
          type: string
        status:
          type: string
        supplier_system_status:
          type: string
        last_updated_at:
          type: string
          format: date-time
    Acknowledgement:
      type: object
      properties:
        acknowledgement_id:
          type: string
        supplier_po_id:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - accepted
          - pending_review
          - rejected
        issued_at:
          type: string
          format: date-time
        lines:
          type: array
          items:
            type: object
            properties:
              lineNumber:
                type: integer
              status:
                type: string
              reason:
                type: string
    BuyerEvent:
      type: object
      properties:
        event_id:
          type: string
        event_name:
          type: string
        occurred_at:
          type: string
          format: date-time
        data:
          type: object
          additionalProperties: true
    CatalogItem:
      type: object
      properties:
        sku:
          type: string
        name:
          type: string
        uom:
          type: string
        description:
          type: string
        status:
          type: string
    PricingItem:
      type: object
      properties:
        sku:
          type: string
        unitPrice:
          type: number
        currency:
          type: string
        uom:
          type: string
        effectiveTo:
          type: string
          format: date-time
    AvailabilityResponse:
      type: object
      properties:
        sku:
          type: string
        band:
          type: string
          enum:
          - available
          - limited
          - unavailable
          - backorder_available
          - discontinued
          - lead_time_required
        leadTimeDays:
          type: integer
    WebhookEndpointCreate:
      type: object
      required:
      - url
      - event_filters
      properties:
        url:
          type: string
          format: uri
        event_filters:
          type: array
          items:
            type: string
        description:
          type: string
    WebhookEndpointCreated:
      allOf:
      - $ref: '#/components/schemas/WebhookEndpoint'
      - type: object
        properties:
          signing_secret:
            type: string
            description: Shown once.
    WebhookEndpoint:
      type: object
      properties:
        endpoint_id:
          type: string
        url:
          type: string
        event_filters:
          type: array
          items:
            type: string
        status:
          type: string
    ErrorResponse:
      type: object
      properties:
        error:
          type: object
          properties:
            code:
              type: string
            message:
              type: string
            correlation_id:
              type: string
            details:
              type: array
              items:
                type: object
                properties:
                  path:
                    type: string
                  code:
                    type: string
                  message:
                    type: string
