openapi: 3.1.0
info:
  title: UCP API
  version: 0.1.0-draft
  description: |
    Universal Commerce Protocol Adapter (UCP).

    Contract notes:
    - API Gateway base path: `/ucp`
    - Dual auth: admin routes use session/api_key (x-session-guid or x-api-key); platform routes use client_id/client_secret in body.
    - `GET /stat` requires no authentication.
    - `GET /.well-known/ucp?orgcode=X` requires no authentication (public capability profile).
    - Platform credentials are managed via admin routes (/platform/*).
    - Checkout sessions are managed via platform routes (/checkout/*).
    - Phase 1: Checkout capability. Phase 2: Order webhooks. Phase 3: Identity Linking.
  license:
    name: Proprietary
    url: https://g3nretailstack.com/license
servers:
  - url: https://api.g3nretailstack.com/ucp
security: []
components:
  securitySchemes:
    sessionAuth:
      type: apiKey
      in: header
      name: x-session-guid
    apiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
    platformAuth:
      type: apiKey
      in: body
      name: client_id
      description: Platform auth via client_id + client_secret in request body.
    bearerAuth:
      type: http
      scheme: bearer
      description: OAuth 2.0 Bearer token for identity-linked operations.
  schemas:
    BuildMeta:
      type: object
      properties:
        build_major: { type: string }
        build_minor: { type: string }
        build_id: { type: string }
    Stats:
      type: object
      properties:
        call: { type: string }
        service: { type: string, enum: [ucp] }
        timestamp_utc: { type: string, format: date-time }
        build: { $ref: '#/components/schemas/BuildMeta' }
        request_id: { type: string }
    ErrorEnvelope:
      type: object
      properties:
        success: { type: boolean, enum: [false] }
        error:
          type: object
          properties:
            error_code: { type: string }
            http_status: { type: integer }
            retryable: { type: boolean }
            major:
              type: object
              properties:
                tag: { type: string }
                message:
                  type: object
                  properties:
                    en_US: { type: string }
        stats: { $ref: '#/components/schemas/Stats' }
    CheckoutLineItem:
      type: object
      required: [title, quantity, unit_price_cents, currency]
      properties:
        line_id: { type: string }
        sku: { type: string }
        product_code: { type: string }
        variant_code: { type: string }
        title: { type: string }
        quantity: { type: integer, minimum: 1 }
        unit_price_cents: { type: integer, minimum: 0 }
        currency: { type: string }
    CheckoutBuyer:
      type: object
      properties:
        email: { type: string }
        phone: { type: string }
        first_name: { type: string }
        last_name: { type: string }
        address:
          type: object
          properties:
            line1: { type: string }
            line2: { type: string }
            city: { type: string }
            state: { type: string }
            postal_code: { type: string }
            country: { type: string }
    CheckoutPricing:
      type: object
      properties:
        subtotal_cents: { type: integer }
        tax_cents: { type: integer }
        shipping_cents: { type: integer }
        discount_cents: { type: integer }
        total_cents: { type: integer }
        currency: { type: string }
    CheckoutSession:
      type: object
      properties:
        session_id: { type: string }
        status: { type: string, enum: [incomplete, requires_escalation, ready_for_complete, complete_in_progress, completed, canceled] }
        line_items: { type: array, items: { $ref: '#/components/schemas/CheckoutLineItem' } }
        buyer: { $ref: '#/components/schemas/CheckoutBuyer' }
        pricing: { $ref: '#/components/schemas/CheckoutPricing' }
        payment_status: { type: string, enum: [none] }
        channel_code: { type: string, enum: [ucp] }
        scm_order_guid: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        expires_at_epoch: { type: integer }
    Platform:
      type: object
      properties:
        platform_guid: { type: string }
        client_id: { type: string }
        caption: { type: string }
        status: { type: string, enum: [active, revoked] }
        scopes: { type: array, items: { type: string } }
        callback_url: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
    AuthCodeRequest:
      type: object
      required: [platform_guid, customer_guid]
      properties:
        platform_guid: { type: string }
        customer_guid: { type: string }
        scopes: { type: array, items: { type: string, enum: ['ucp:checkout_session', 'ucp:order_read', 'ucp:customer_read'] } }
        redirect_uri: { type: string }
        code_challenge: { type: string }
    AuthCodeResponse:
      type: object
      properties:
        code: { type: string }
        expires_in: { type: integer }
        scopes: { type: array, items: { type: string } }
        platform_guid: { type: string }
        customer_guid: { type: string }
    TokenRequest:
      type: object
      required: [client_id, client_secret, grant_type]
      properties:
        client_id: { type: string }
        client_secret: { type: string }
        grant_type: { type: string, enum: [authorization_code, refresh_token] }
        code: { type: string }
        redirect_uri: { type: string }
        code_verifier: { type: string }
        refresh_token: { type: string }
    TokenResponse:
      type: object
      properties:
        access_token: { type: string }
        token_type: { type: string, enum: [Bearer] }
        expires_in: { type: integer }
        refresh_token: { type: string }
        scope: { type: string }
    RevokeRequest:
      type: object
      required: [client_id, client_secret, token]
      properties:
        client_id: { type: string }
        client_secret: { type: string }
        token: { type: string }
        token_type_hint: { type: string, enum: [access_token, refresh_token] }
    UserinfoResponse:
      type: object
      properties:
        sub: { type: string }
        platform_guid: { type: string }
        scopes: { type: array, items: { type: string } }
        customer_code: { type: string }
        email: { type: string }
        phone: { type: string }
        first_name: { type: string }
        last_name: { type: string }
        status: { type: string }
    IdentityLink:
      type: object
      properties:
        platform_guid: { type: string }
        customer_guid: { type: string }
        scopes: { type: array, items: { type: string } }
        linked_at: { type: string, format: date-time }
        linked_by: { type: string }
        status: { type: string, enum: [active, revoked] }
        revoked_at: { type: string, format: date-time }
    LinkListResponse:
      type: object
      properties:
        items: { type: array, items: { $ref: '#/components/schemas/IdentityLink' } }
        count: { type: integer }
        next_token: {}
paths:
  /stat:
    get:
      operationId: ucpStat
      summary: Health/build check
      x-route-class: Tier A
      x-qps-target: 1000
      x-concurrency-target: 1000
      x-latency-p95-ms: 100
      responses:
        '200':
          description: OK
  /.well-known/ucp:
    get:
      operationId: ucpProfile
      summary: UCP capability profile per org
      x-route-class: Tier A
      x-qps-target: 500
      x-concurrency-target: 500
      x-latency-p95-ms: 200
      parameters:
        - name: orgcode
          in: query
          required: true
          schema: { type: string }
      responses:
        '200':
          description: UCP capability profile
  /checkout/create:
    post:
      operationId: ucpCheckoutCreate
      summary: Create checkout session with cart
      x-route-class: Tier B
      x-qps-target: 200
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-idempotency: caller-key
      security: [{ platformAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              x-idempotency-scope: orgcode+route+idempotency_key
              x-idempotency-retention-hours: 24
              x-idempotency-replay: return_original_response
              required: [client_id, client_secret, line_items]
              properties:
                client_id: { type: string }
                client_secret: { type: string }
                line_items: { type: array, items: { $ref: '#/components/schemas/CheckoutLineItem' } }
                buyer: { $ref: '#/components/schemas/CheckoutBuyer' }
                idempotency_key: { type: string }
      responses:
        '200':
          description: Checkout session created
  /checkout/get:
    post:
      operationId: ucpCheckoutGet
      summary: Get checkout session state
      x-route-class: Tier A
      x-qps-target: 500
      x-concurrency-target: 500
      x-latency-p95-ms: 200
      security: [{ platformAuth: [] }]
      responses:
        '200':
          description: Checkout session
  /checkout/update:
    post:
      operationId: ucpCheckoutUpdate
      summary: Full cart replacement
      x-route-class: Tier B
      x-qps-target: 200
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      security: [{ platformAuth: [] }]
      responses:
        '200':
          description: Updated session
  /checkout/complete:
    post:
      operationId: ucpCheckoutComplete
      summary: Finalize checkout → SCM order
      x-route-class: Tier C
      x-qps-target: 100
      x-concurrency-target: 100
      x-latency-p95-ms: 2000
      x-latency-p99-ms: 5000
      x-idempotency: natural
      security: [{ platformAuth: [] }]
      responses:
        '200':
          description: Order created
  /checkout/cancel:
    post:
      operationId: ucpCheckoutCancel
      summary: Cancel checkout session
      x-route-class: Tier B
      x-qps-target: 200
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-idempotency: natural
      security: [{ platformAuth: [] }]
      responses:
        '200':
          description: Session canceled
  /platform/register:
    post:
      operationId: ucpPlatformRegister
      summary: Register platform credentials
      x-route-class: Tier C
      x-qps-target: 10
      x-concurrency-target: 10
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      responses:
        '200':
          description: Platform registered (includes client_secret — shown once)
  /platform/get:
    post:
      operationId: ucpPlatformGet
      summary: Get platform details
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 100
      x-latency-p95-ms: 200
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      responses:
        '200':
          description: Platform details
  /platform/list:
    post:
      operationId: ucpPlatformList
      summary: List org platforms
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 100
      x-latency-p95-ms: 200
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      responses:
        '200':
          description: Platform list
  /platform/rotate:
    post:
      operationId: ucpPlatformRotate
      summary: Rotate client secret
      x-route-class: Tier C
      x-qps-target: 10
      x-concurrency-target: 10
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      responses:
        '200':
          description: New secret (shown once)
  /platform/revoke:
    post:
      operationId: ucpPlatformRevoke
      summary: Revoke platform
      x-route-class: Tier C
      x-qps-target: 10
      x-concurrency-target: 10
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      responses:
        '200':
          description: Platform revoked
  /config/set:
    post:
      operationId: ucpConfigSet
      summary: Set UCP org config
      x-route-class: Tier C
      x-qps-target: 10
      x-concurrency-target: 10
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      responses:
        '200':
          description: Config updated
  /config/get:
    post:
      operationId: ucpConfigGet
      summary: Get UCP org config
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 100
      x-latency-p95-ms: 200
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }, { platformAuth: [] }]
      responses:
        '200':
          description: Config
  /webhook/config/set:
    post:
      operationId: ucpWebhookConfigSet
      summary: Set webhook event filters per platform
      x-route-class: Tier B
      x-qps-target: 50
      x-concurrency-target: 50
      x-latency-p95-ms: 300
      x-idempotent: true
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      responses:
        '200':
          description: Webhook config updated
  /webhook/config/get:
    post:
      operationId: ucpWebhookConfigGet
      summary: Get webhook config
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 100
      x-latency-p95-ms: 200
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      responses:
        '200':
          description: Webhook config
  /webhook/test:
    post:
      operationId: ucpWebhookTest
      summary: Send test webhook to platform callback_url
      x-route-class: Tier C
      x-qps-target: 10
      x-concurrency-target: 10
      x-latency-p95-ms: 7000
      x-latency-p99-ms: 10000
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      responses:
        '200':
          description: Test delivery result
  /identity/.well-known/oauth-authorization-server:
    get:
      operationId: ucpIdentityDiscovery
      summary: RFC 8414 OAuth Authorization Server Metadata
      x-route-class: Tier A
      x-qps-target: 500
      x-concurrency-target: 500
      x-latency-p95-ms: 50
      parameters:
        - name: orgcode
          in: query
          required: true
          schema: { type: string }
      responses:
        '200':
          description: OAuth metadata document
  /identity/authorize:
    post:
      operationId: ucpIdentityAuthorize
      summary: Admin generates auth code for customer↔platform link
      x-route-class: Tier C
      x-qps-target: 50
      x-concurrency-target: 50
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AuthCodeRequest' }
      responses:
        '200':
          description: Authorization code issued
  /identity/token:
    post:
      operationId: ucpIdentityToken
      summary: Exchange auth code for access + refresh tokens
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 100
      x-latency-p95-ms: 500
      security: [{ platformAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/TokenRequest' }
      responses:
        '200':
          description: OAuth token response
          content:
            application/json:
              schema: { $ref: '#/components/schemas/TokenResponse' }
  /identity/revoke:
    post:
      operationId: ucpIdentityRevoke
      summary: Revoke access or refresh token (RFC 7009)
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 100
      x-latency-p95-ms: 300
      security: [{ platformAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/RevokeRequest' }
      responses:
        '200':
          description: Token revoked (always 200 per RFC 7009)
  /identity/userinfo:
    post:
      operationId: ucpIdentityUserinfo
      summary: Get linked customer info via bearer token
      x-route-class: Tier B
      x-qps-target: 200
      x-concurrency-target: 200
      x-latency-p95-ms: 300
      security: [{ bearerAuth: [] }]
      responses:
        '200':
          description: Customer info
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UserinfoResponse' }
  /identity/link/list:
    post:
      operationId: ucpIdentityLinkList
      summary: List identity links per platform or customer
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 100
      x-latency-p95-ms: 200
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                platform_guid: { type: string }
                customer_guid: { type: string }
                limit: { type: integer, default: 20 }
                next_token: {}
      responses:
        '200':
          description: Identity links
          content:
            application/json:
              schema: { $ref: '#/components/schemas/LinkListResponse' }
  /identity/link/revoke:
    post:
      operationId: ucpIdentityLinkRevoke
      summary: Admin revokes an identity link (cascades to tokens)
      x-route-class: Tier C
      x-qps-target: 50
      x-concurrency-target: 50
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      security: [{ sessionAuth: [] }, { apiKeyAuth: [] }]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [platform_guid, customer_guid]
              properties:
                platform_guid: { type: string }
                customer_guid: { type: string }
      responses:
        '200':
          description: Link revoked
