openapi: 3.1.0
info:
  title: USM API
  version: 0.1.0-draft
  description: |
    User Session Management (USM).

    Contract notes:
    - API Gateway base path: `/usm`
    - All routes are `POST` JSON endpoints.
    - `POST /session/create` is credentialed (requires `email` + `passcode`) and issues a new `session_guid`.
    - Email inputs are canonicalized (trim + lowercase) before UAS lookups.
    - All other routes require a valid `session_guid` (bearer secret). A `session_guid` is only valid while the session is `active`.
    - `POST /session/list` accepts `session_guid` in the JSON body, and also accepts `x-session-guid` in headers (compat).
    - Device/session management:
      - `POST /session/logout_other_devices` dooms all other `active` sessions for the caller user.
      - `POST /session/logout_everywhere` sets a per-user revoke marker and best-effort dooms `active` sessions.
        Sessions created before the revoke marker are rejected with `revoked` on validate/list.
    - `session_guid` must never be emitted outside of USM session APIs; use `session_fingerprint` (SHA-256) for correlation in `stats`/events/audits.
  license:
    name: Proprietary
    url: https://g3nretailstack.com/license
servers:
  - url: https://api.g3nretailstack.com/usm
security:
  - sessionAuth: []
components:
  securitySchemes:
    sessionAuth:
      type: apiKey
      in: header
      name: x-session-guid
    apiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
  schemas:
    BuildMeta:
      type: object
      properties:
        build_major: { type: string }
        build_minor: { type: string }
        build_id: { type: string }
      required: [build_major, build_minor, build_id]
    Stats:
      type: object
      properties:
        call: { type: string }
        service: { type: string, enum: [usm] }
        request_id: { type: string }
        timestamp_utc: { type: string, format: date-time }
        build: { $ref: '#/components/schemas/BuildMeta' }
        latency_ms: { type: integer }
        bandwidth_in_bytes: { type: integer }
        bandwidth_out_bytes: { type: integer }
        other_service_calls: { type: integer }
        actor: { type: string }
        session_fingerprint:
          type: string
          description: Non-reversible SHA-256 fingerprint of a caller-provided `session_guid` (never an auth credential).
        api_key_fingerprint:
          type: string
          description: Non-reversible SHA-256 fingerprint of a caller-provided `api_key` (never an auth credential).
        user_guid: { type: string }
      required: [call, service, timestamp_utc, build]
    ErrorMessage:
      type: object
      properties:
        en_US: { type: string }
      required: [en_US]
    ErrorTag:
      type: object
      properties:
        tag: { type: string }
        message: { $ref: '#/components/schemas/ErrorMessage' }
      required: [tag, message]
    Error:
      type: object
      properties:
        error_code: { type: string }
        http_status: { type: integer }
        retryable: { type: boolean }
        request_id: { type: string }
        trace_id: { type: string }
        major: { $ref: '#/components/schemas/ErrorTag' }
        minor: { $ref: '#/components/schemas/ErrorTag' }
        details: {}
      required: [major]
    Envelope:
      type: object
      properties:
        success: { type: boolean }
        data: {}
        stats: { $ref: '#/components/schemas/Stats' }
        error: { $ref: '#/components/schemas/Error' }
        revision:
          type: string
          description: Present for some services/records; USM sessions are revisionless.
      required: [success]
    ErrorResponse:
      allOf:
        - $ref: '#/components/schemas/Envelope'
        - type: object
          properties:
            success: { type: boolean, const: false }
          required: [success, error, stats]
    OkResponse:
      allOf:
        - $ref: '#/components/schemas/Envelope'
        - type: object
          properties:
            success: { type: boolean, const: true }
            data: {}
          required: [success, data, stats]

    SessionStatus:
      type: string
      enum: [active, doomed]

    UsmSessionCreateRequest:
      type: object
      properties:
        email: { type: string, format: email }
        passcode: { type: string }
        caption: { type: string }
        session_label: { type: string }
        ttl_seconds:
          type: integer
          description: Sliding TTL in seconds.
          minimum: 1
          maximum: 86400
          default: 3600
        ttl_refresh_enabled:
          type: boolean
          description: When true (default), successful `validate`/`list` refreshes expiry.
          default: true
        actor: { type: string }
        reason: { type: string }
      required: [email, passcode]

    UsmSessionCreateData:
      type: object
      properties:
        session_guid: { type: string }
        user_id: { type: string }
        status: { $ref: '#/components/schemas/SessionStatus' }
        expires_at_utc: { type: string, format: date-time }
        ttl_seconds: { type: integer }
        ttl_refresh_enabled: { type: boolean }
        caption: { type: string }
        label: { type: string, nullable: true }
      required: [session_guid, user_id, status, expires_at_utc, ttl_seconds, ttl_refresh_enabled, caption]

    UsmSessionValidateRequest:
      type: object
      properties:
        session_guid: { type: string }
        actor: { type: string }
        reason: { type: string }
      required: [session_guid]

    UsmSessionValidateData:
      type: object
      properties:
        session_guid: { type: string }
        user_id: { type: string }
        status: { type: string, enum: [active] }
        expires_at_utc: { type: string, format: date-time }
        ttl_seconds: { type: integer }
        ttl_refresh_enabled: { type: boolean }
        caption: { type: string }
        label: { type: string, nullable: true }
        last_touched_at: { type: string, format: date-time }
      required: [session_guid, user_id, status, expires_at_utc, ttl_seconds, ttl_refresh_enabled, caption, last_touched_at]

    UsmSessionCloseRequest:
      type: object
      properties:
        session_guid: { type: string }
        actor: { type: string }
        reason: { type: string }
      required: [session_guid]

    UsmSessionCloseData:
      type: object
      properties:
        session_guid: { type: string }
        user_id: { type: string }
        status: { type: string, enum: [doomed] }
        doom_reason: { type: string }
        doomed_at_utc: { type: string, format: date-time }
      required: [session_guid, user_id, status, doom_reason, doomed_at_utc]

    UsmSessionGetRequest:
      type: object
      properties:
        session_guid: { type: string }
        include_archived: { type: boolean, default: false }
        actor: { type: string }
      required: [session_guid]

    UsmSessionRecord:
      type: object
      properties:
        session_guid: { type: string }
        session_fingerprint: { type: string }
        user_id: { type: string }
        status: { $ref: '#/components/schemas/SessionStatus' }
        doom_reason: { type: string }
        doomed_at_utc: { type: string, format: date-time }
        expires_at_utc: { type: string, format: date-time }
        last_touched_at: { type: string, format: date-time }
        ttl_seconds: { type: integer }
        ttl_refresh_enabled: { type: boolean }
        caption: { type: string }
        label: { type: string, nullable: true }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
      required: [session_guid, user_id, status, expires_at_utc, last_touched_at, ttl_seconds, ttl_refresh_enabled, caption, created_at, updated_at]

    UsmSessionGetSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmSessionRecord' }
          required: [data]

    UsmSessionListRequest:
      type: object
      properties:
        session_guid:
          type: string
          description: |
            Caller session GUID (required unless provided via header `x-session-guid`).
            Must be an `active` session.
        status:
          type: string
          enum: [active, doomed, all]
          default: active
        limit:
          type: integer
          minimum: 1
          maximum: 256
          default: 8
        next_token: { type: string }
        next_token_active: { type: string }
        next_token_doomed: { type: string }
        include_archived: { type: boolean, default: false }
        archive_next_token: { type: string }
        archived_since: { type: string, format: date-time }
        archived_until: { type: string, format: date-time }
        since_expires_at_utc: { type: string, format: date-time }
        until_expires_at_utc: { type: string, format: date-time }
        label_prefix: { type: string }
        label_contains: { type: string }
        caption_contains: { type: string }
        actor: { type: string }

    UsmSessionListData:
      type: object
      properties:
        sessions:
          type: array
          items: { $ref: '#/components/schemas/UsmSessionRecord' }
        next_token: { type: string, nullable: true }
        sessions_active:
          type: array
          items: { $ref: '#/components/schemas/UsmSessionRecord' }
        sessions_doomed:
          type: array
          items: { $ref: '#/components/schemas/UsmSessionRecord' }
        next_token_active: { type: string, nullable: true }
        next_token_doomed: { type: string, nullable: true }
        archived_sessions:
          type: array
          items: { $ref: '#/components/schemas/UsmSessionRecord' }
        archive_next_token: { type: string, nullable: true }
      required: [sessions]

    UsmSessionListSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmSessionListData' }
          required: [data]

    UsmSessionLogoutOtherDevicesRequest:
      type: object
      properties:
        session_guid: { type: string }
        actor: { type: string }
        reason: { type: string }
      required: [session_guid]

    UsmSessionLogoutOtherDevicesData:
      type: object
      properties:
        user_id: { type: string }
        doomed_sessions: { type: integer }
        scanned_active_sessions: { type: integer }
        skipped_current_session: { type: boolean }
      required: [user_id, doomed_sessions, scanned_active_sessions, skipped_current_session]

    UsmSessionLogoutOtherDevicesSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmSessionLogoutOtherDevicesData' }
          required: [data]

    UsmSessionLogoutEverywhereRequest:
      type: object
      properties:
        session_guid: { type: string }
        actor: { type: string }
        reason: { type: string }
      required: [session_guid]

    UsmSessionLogoutEverywhereData:
      type: object
      properties:
        user_id: { type: string }
        revoke_before_utc: { type: string, format: date-time }
        doomed_sessions: { type: integer }
        scanned_active_sessions: { type: integer }
      required: [user_id, revoke_before_utc, doomed_sessions, scanned_active_sessions]

    UsmSessionLogoutEverywhereSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmSessionLogoutEverywhereData' }
          required: [data]

    ServiceAccountStatus:
      type: string
      enum: [active, doomed]

    ApiKeyStatus:
      type: string
      enum: [active, doomed]

    UsmServiceAccountCreateRequest:
      type: object
      properties:
        session_guid: { type: string }
        orgcode: { type: string }
        caption: { type: string }
        roles:
          type: array
          description: |
            Service-account roles. Allowed values are `pvv`, `pma`, `vca`, `owner`.
            Synonyms are accepted and canonicalized: "Product and Vendor Viewer"→`pvv`, "Product Model Administrator"→`pma`, "Vendor Contract Administrator"→`vca`.
          items:
            type: string
            enum: [pvv, pma, vca, owner, "Product and Vendor Viewer", "Product Model Administrator", "Vendor Contract Administrator"]
        actor: { type: string }
        reason: { type: string }
      required: [session_guid, orgcode, roles]

    UsmServiceAccount:
      type: object
      properties:
        service_account_guid: { type: string }
        orgcode: { type: string }
        org_guid: { type: string }
        status: { $ref: '#/components/schemas/ServiceAccountStatus' }
        roles:
          type: array
          items: { type: string, enum: [pvv, pma, vca, owner] }
        caption: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        doomed_at_utc: { type: string, format: date-time }
        doom_reason: { type: string }
      required: [service_account_guid, orgcode, org_guid, status, roles, caption, created_at]

    UsmServiceAccountCreateSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmServiceAccount' }
          required: [data]

    UsmServiceAccountListRequest:
      type: object
      properties:
        session_guid: { type: string }
        orgcode: { type: string }
        status: { type: string, enum: [active, doomed, all], default: active }
        limit: { type: integer, minimum: 1, maximum: 256, default: 8 }
        next_token: { type: string }
        actor: { type: string }
      required: [orgcode]

    UsmServiceAccountListData:
      type: object
      properties:
        service_accounts:
          type: array
          items: { $ref: '#/components/schemas/UsmServiceAccount' }
        next_token: { type: string, nullable: true }
      required: [service_accounts]

    UsmServiceAccountListSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmServiceAccountListData' }
          required: [data]

    UsmServiceAccountStatusRequest:
      type: object
      properties:
        session_guid: { type: string }
        orgcode: { type: string }
        service_account_guid: { type: string }
        status: { type: string, enum: [doomed] }
        actor: { type: string }
        reason: { type: string }
      required: [session_guid, orgcode, service_account_guid, status]

    UsmServiceAccountStatusSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmServiceAccount' }
          required: [data]

    UsmApiKeyCreateRequest:
      type: object
      properties:
        session_guid: { type: string }
        orgcode: { type: string }
        service_account_guid: { type: string }
        caption: { type: string }
        actor: { type: string }
        reason: { type: string }
      required: [session_guid, orgcode, service_account_guid]

    UsmApiKeyRecord:
      type: object
      properties:
        api_key_id: { type: string }
        api_key_fingerprint: { type: string }
        service_account_guid: { type: string }
        orgcode: { type: string }
        org_guid: { type: string }
        status: { $ref: '#/components/schemas/ApiKeyStatus' }
        revoked_by_marker:
          type: boolean
          description: Present and true when `revoke_before_utc` invalidates this key (service-account revoke-all marker).
        revoked_by_org_marker:
          type: boolean
          description: Present and true when `org_revoke_before_utc` invalidates this key (org-level revoke-all marker).
        expired_by_policy:
          type: boolean
          description: Present and true when `org_api_key_max_age_seconds` invalidates this key (org-level expiry policy).
        caption: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        doomed_at_utc: { type: string, format: date-time }
        doom_reason: { type: string }
      required: [api_key_id, api_key_fingerprint, service_account_guid, orgcode, org_guid, status, caption, created_at]

    UsmApiKeyCreateData:
      allOf:
        - $ref: '#/components/schemas/UsmApiKeyRecord'
        - type: object
          properties:
            api_key:
              type: string
              description: Full API key secret (returned only once on create).
          required: [api_key]

    UsmApiKeyCreateSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmApiKeyCreateData' }
          required: [data]

    UsmApiKeyListRequest:
      type: object
      properties:
        session_guid: { type: string }
        orgcode: { type: string }
        service_account_guid: { type: string }
        status: { type: string, enum: [active, doomed, all], default: active }
        limit: { type: integer, minimum: 1, maximum: 256, default: 8 }
        next_token: { type: string }
        actor: { type: string }
      required: [session_guid, orgcode, service_account_guid]

    UsmApiKeyListData:
      type: object
      properties:
        api_keys:
          type: array
          items: { $ref: '#/components/schemas/UsmApiKeyRecord' }
        revoke_before_utc:
          type: string
          format: date-time
          nullable: true
          description: |
            Service-account revoke-all marker. When set, keys with `created_at < revoke_before_utc` are invalid (even if their `status` is still `active`).
        org_revoke_before_utc:
          type: string
          format: date-time
          nullable: true
          description: Org-level revoke-all marker. When set, all keys in the org with `created_at < org_revoke_before_utc` are invalid.
        org_api_key_max_age_seconds:
          type: integer
          nullable: true
          description: |
            Org-level API key expiry policy. When set, keys with `created_at` older than `now - org_api_key_max_age_seconds` are invalid.
        next_token: { type: string, nullable: true }
      required: [api_keys]

    UsmApiKeyListSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmApiKeyListData' }
          required: [data]

    UsmApiKeyPolicySetRequest:
      type: object
      properties:
        session_guid: { type: string }
        orgcode: { type: string }
        api_key_max_age_seconds:
          type: integer
          nullable: true
          description: Set to null to disable org-level expiry (default).
        actor: { type: string }
        reason: { type: string }
      required: [session_guid, orgcode, api_key_max_age_seconds]

    UsmApiKeyPolicySetData:
      type: object
      properties:
        orgcode: { type: string }
        org_guid: { type: string }
        revoke_before_utc: { type: string, format: date-time, nullable: true }
        api_key_max_age_seconds: { type: integer, nullable: true }
        updated_at: { type: string, format: date-time }
      required: [orgcode, org_guid, updated_at]

    UsmApiKeyPolicySetSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmApiKeyPolicySetData' }
          required: [data]

    UsmApiKeyRevokeRequest:
      type: object
      properties:
        session_guid: { type: string }
        orgcode: { type: string }
        api_key_id: { type: string }
        actor: { type: string }
        reason: { type: string }
      required: [session_guid, orgcode, api_key_id]

    UsmApiKeyRevokeSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmApiKeyRecord' }
          required: [data]

    UsmApiKeyRevokeAllRequest:
      type: object
      properties:
        session_guid: { type: string }
        orgcode: { type: string }
        service_account_guid: { type: string }
        actor: { type: string }
        reason: { type: string }
      required: [session_guid, orgcode, service_account_guid]

    UsmApiKeyRevokeAllData:
      type: object
      properties:
        orgcode: { type: string }
        org_guid: { type: string }
        service_account_guid: { type: string }
        revoke_before_utc: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
      required: [orgcode, org_guid, service_account_guid, revoke_before_utc, updated_at]

    UsmApiKeyRevokeAllSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmApiKeyRevokeAllData' }
          required: [data]

    UsmApiKeyRevokeAllOrgRequest:
      type: object
      properties:
        session_guid: { type: string }
        orgcode: { type: string }
        actor: { type: string }
        reason: { type: string }
      required: [session_guid, orgcode]

    UsmApiKeyRevokeAllOrgData:
      type: object
      properties:
        orgcode: { type: string }
        org_guid: { type: string }
        revoke_before_utc: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
      required: [orgcode, org_guid, revoke_before_utc, updated_at]

    UsmApiKeyRevokeAllOrgSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmApiKeyRevokeAllOrgData' }
          required: [data]

    UsmApiKeyValidateRequest:
      type: object
      properties:
        api_key:
          type: string
          description: |
            API key (bearer secret). Prefer providing via header `x-api-key`; body form is accepted for convenience.
        actor: { type: string }
        reason: { type: string }

    UsmApiKeyValidateData:
      type: object
      properties:
        principal_type: { type: string, enum: [service_account] }
        api_key_id: { type: string }
        api_key_fingerprint: { type: string }
        service_account_guid: { type: string }
        orgcode: { type: string }
        org_guid: { type: string }
        org_status: { type: string }
        roles:
          type: array
          items: { type: string }
      required: [principal_type, api_key_id, api_key_fingerprint, service_account_guid, orgcode, org_guid, org_status, roles]

    UsmApiKeyValidateSuccess:
      allOf:
        - $ref: '#/components/schemas/OkResponse'
        - type: object
          properties:
            data: { $ref: '#/components/schemas/UsmApiKeyValidateData' }
          required: [data]

paths:
  /session/create:
    post:
      operationId: usmSessionCreate
      summary: Create a new session (email + passcode)
      description: |
        Create a new session (email + passcode). Session/API-key operations use body auth; follow the USM
        surface placement rules. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier B (p95 300ms).
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmSessionCreateRequest' }
            examples:
              basic:
                value:
                  email: user@example.com
                  passcode: Passw0rd!
                  session_label: macbook
      responses:
        '200':
          description: Session created
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/UsmSessionCreateData' }
                    required: [data]
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /session/validate:
    post:
      operationId: usmSessionValidate
      summary: Validate a session (and refresh sliding TTL)
      description: |
        Validate a session (and refresh sliding TTL). Session/API-key operations use body auth; follow the
        USM surface placement rules. Route class Tier C (p95 150ms, p99 400ms).
      x-route-class: Tier C
      x-qps-target: 3000
      x-concurrency-target: 4000
      x-latency-p95-ms: 150
      x-latency-p99-ms: 400
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmSessionValidateRequest' }
      responses:
        '200':
          description: Session is valid (active)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/UsmSessionValidateData' }
                    required: [data]
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /session/close:
    post:
      operationId: usmSessionClose
      summary: Close a session (doom as closed)
      description: |
        Close a session (doom as closed). Session/API-key operations use body auth; follow the USM surface
        placement rules. Route class Tier B (p95 300ms).
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmSessionCloseRequest' }
      responses:
        '200':
          description: Session closed
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/UsmSessionCloseData' }
                    required: [data]
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /session/get:
    post:
      operationId: usmSessionGet
      summary: Get session metadata (optionally include archived)
      description: |
        Get session metadata (optionally include archived). Session/API-key operations use body auth; follow
        the USM surface placement rules. Route class Tier B (p95 300ms).
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmSessionGetRequest' }
      responses:
        '200':
          description: Session found
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmSessionGetSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /session/list:
    post:
      operationId: usmSessionList
      summary: List sessions for the caller (self-only)
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      description: |
        Lists sessions for the user who owns the caller `session_guid`.

        Notes:
        - Requires an `active` session.
        - Accepts `session_guid` in body or via header `x-session-guid`.
      parameters:
        - name: x-session-guid
          in: header
          required: false
          schema: { type: string }
          description: Optional session GUID header (compat with `POST /session/list`).
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmSessionListRequest' }
      responses:
        '200':
          description: Sessions listed
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmSessionListSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /session/logout_other_devices:
    post:
      operationId: usmSessionLogoutOtherDevices
      summary: Logout other devices (doom other active sessions)
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      description: |
        Dooms all other `active` sessions for the user who owns the caller `session_guid`.
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmSessionLogoutOtherDevicesRequest' }
      responses:
        '200':
          description: Sessions revoked
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmSessionLogoutOtherDevicesSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /session/logout_everywhere:
    post:
      operationId: usmSessionLogoutEverywhere
      summary: Logout everywhere (revoke all sessions)
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      description: |
        Sets a per-user revoke marker and best-effort dooms `active` sessions.

        All sessions created before the revoke marker are rejected on `validate` and `list` with reason `revoked`.
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmSessionLogoutEverywhereRequest' }
      responses:
        '200':
          description: Sessions revoked
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmSessionLogoutEverywhereSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /service_account/create:
    post:
      operationId: usmServiceAccountCreate
      summary: Create a service account (org owner only)
      description: |
        Create a service account (org owner only). Session/API-key operations use body auth; follow the USM
        surface placement rules. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmServiceAccountCreateRequest' }
      responses:
        '200':
          description: Service account created
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmServiceAccountCreateSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /service_account/list:
    post:
      operationId: usmServiceAccountList
      summary: List service accounts for an org (org owner only)
      description: |
        List service accounts for an org (org owner only). Session/API-key operations use body auth; follow
        the USM surface placement rules. Paginated with limit/next_token (default 8; clamp 1–256). Route
        class Tier B (p95 300ms).
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      parameters:
        - name: x-session-guid
          in: header
          required: false
          schema: { type: string }
          description: Optional session GUID header (compat with `POST /service_account/list`).
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmServiceAccountListRequest' }
      responses:
        '200':
          description: Service accounts listed
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmServiceAccountListSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /service_account/status:
    post:
      operationId: usmServiceAccountStatus
      summary: Doom a service account (revokes all keys)
      description: |
        Doom a service account (revokes all keys). Session/API-key operations use body auth; follow the USM
        surface placement rules. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmServiceAccountStatusRequest' }
      responses:
        '200':
          description: Service account updated
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmServiceAccountStatusSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /api_key/create:
    post:
      operationId: usmApiKeyCreate
      summary: Create an API key for a service account (secret returned once)
      description: |
        Create an API key for a service account (secret returned once). Session/API-key operations use body
        auth; follow the USM surface placement rules. If this updates a revisioned record, expected_revision
        is required (428 if missing; 409 on mismatch). Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmApiKeyCreateRequest' }
      responses:
        '200':
          description: API key created
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmApiKeyCreateSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /api_key/list:
    post:
      operationId: usmApiKeyList
      summary: List API keys for a service account (org owner only)
      description: |
        List API keys for a service account (org owner only). Session/API-key operations use body auth;
        follow the USM surface placement rules. Paginated with limit/next_token (default 8; clamp 1–256).
        Route class Tier B (p95 300ms).
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmApiKeyListRequest' }
      responses:
        '200':
          description: API keys listed
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmApiKeyListSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /api_key/revoke:
    post:
      operationId: usmApiKeyRevoke
      summary: Revoke (doom) an API key (org owner only)
      description: |
        Revoke (doom) an API key (org owner only). Session/API-key operations use body auth; follow the USM
        surface placement rules. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmApiKeyRevokeRequest' }
      responses:
        '200':
          description: API key revoked
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmApiKeyRevokeSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /api_key/revoke_all:
    post:
      operationId: usmApiKeyRevokeAll
      summary: Revoke all keys for a service account (marker; org owner only)
      description: |
        Revoke all keys for a service account (marker; org owner only). Session/API-key operations use body
        auth; follow the USM surface placement rules. If this updates a revisioned record, expected_revision
        is required (428 if missing; 409 on mismatch). Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmApiKeyRevokeAllRequest' }
      responses:
        '200':
          description: Revoke marker updated
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmApiKeyRevokeAllSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /api_key/revoke_all_org:
    post:
      operationId: usmApiKeyRevokeAllOrg
      summary: Revoke all API keys across the org (marker; org owner only)
      description: |
        Revoke all API keys across the org (marker; org owner only). Session/API-key operations use body
        auth; follow the USM surface placement rules. If this updates a revisioned record, expected_revision
        is required (428 if missing; 409 on mismatch). Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmApiKeyRevokeAllOrgRequest' }
      responses:
        '200':
          description: Revoke marker updated
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmApiKeyRevokeAllOrgSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /api_key/policy_set:
    post:
      operationId: usmApiKeyPolicySet
      summary: Set org-level API key policy (expiry) (org owner only)
      description: |
        Set org-level API key policy (expiry) (org owner only). Session/API-key operations use body auth;
        follow the USM surface placement rules. If this updates a revisioned record, expected_revision is
        required (428 if missing; 409 on mismatch). Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmApiKeyPolicySetRequest' }
      responses:
        '200':
          description: Policy updated
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmApiKeyPolicySetSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /api_key/validate:
    post:
      operationId: usmApiKeyValidate
      summary: Validate an API key
      description: |
        Validate an API key. Session/API-key operations use body auth; follow the USM surface placement
        rules. Route class Tier C (p95 150ms, p99 400ms).
      x-route-class: Tier C
      x-qps-target: 3000
      x-concurrency-target: 4000
      x-latency-p95-ms: 150
      x-latency-p99-ms: 400
      security:
        - apiKeyAuth: []
      parameters:
        - name: x-api-key
          in: header
          required: false
          schema: { type: string }
          description: Preferred API key header.
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsmApiKeyValidateRequest' }
      responses:
        '200':
          description: API key is valid
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsmApiKeyValidateSuccess' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
