openapi: 3.1.0
info:
  title: OFM API
  version: 0.1.0-draft
  description: |
    Organization & Facility Management (OFM).

    Contract notes:
    - API Gateway base path: `/ofm`
    - All endpoints require valid auth via either:
      - **Canonical** header `x-session-guid` for human USM sessions (body `session_guid` accepted for compatibility), OR
      - **Canonical** header `x-api-key` for USM service-account API keys (body `api_key` accepted for compatibility).
    - Optional cost attribution header: `x-cccode` is accepted and validated (canonical uppercase, `^[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$`) but is telemetry-only and is **not** merged into domain `cccode` inputs/outputs (OFM already uses `cccode` as the cost-centre identifier). When present, it is parsed as `cccode_attrib`.
    - Org-scoped operations require org association (owner OR active member).
      Anti-enumeration: if a resource exists but the caller is not associated, the API returns `404 not-found`.
    - Mutation governance:
      - Org-level/governance mutations require ownership (or API key role `owner`).
      - Selected facility-scoped mutations may be performed by facility-granted members and API keys:
        - Members: explicit member↔logical assignment + required grants.
        - API keys: explicit service-account↔logical assignment + required grants.
      - Owner principals retain implicit access to facility-scoped routes (no assignment required).
    - Invitations are operator-only direct Lambdas (not exposed via API Gateway) and are not included here.
    - Sales Channels require `locale_codes[]` (>=1). `default_locale_code` auto-defaults when a single locale is provided, otherwise required.
  license:
    name: Proprietary
    url: https://g3nretailstack.com/license
servers:
  - url: https://api.g3nretailstack.com/ofm
security:
  - sessionAuth: []
  - apiKeyAuth: []
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: [ofm] }
        timestamp_utc: { type: string, format: date-time }
        request_id: { type: string }
        build: { $ref: '#/components/schemas/BuildMeta' }
      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 }
      required: [success]
    ErrorResponse:
      allOf:
        - $ref: '#/components/schemas/Envelope'
        - type: object
          properties:
            success: { type: boolean, const: false }
          required: [success, error]
    OkResponse:
      allOf:
        - $ref: '#/components/schemas/Envelope'
        - type: object
          properties:
            success: { type: boolean, const: true }
            data: {}
          required: [success, data, stats]
    NextToken:
      type: object
      description: Opaque pagination cursor (JSON object)
      additionalProperties: true
    SessionRequest:
      type: object
      properties:
        session_guid: { type: string }
        api_key:
          type: string
          description: API key (bearer secret). Prefer providing via header `x-api-key`; body form is accepted for convenience. For API-key principals, read surfaces require an OFM view role (`ofm_view` or implied by `pvv|pma|vca|pmc_view|pmc_publish`); org-level/governance mutations require `owner`; delegated facility-scoped mutations require explicit service-account↔logical assignment + required grants.
        actor: { type: string }
        reason: { type: string }
      oneOf:
        - required: [session_guid]
        - required: [api_key]
    PaginationRequest:
      type: object
      properties:
        limit: { type: integer, minimum: 1, maximum: 256, default: 8 }
        next_token: { $ref: '#/components/schemas/NextToken' }
    ExpectedRevision:
      type: string
      description: Expected revision GUID for optimistic concurrency
    Address:
      type: object
      properties:
        street: { type: string }
        city: { type: string }
        region: { type: string }
        country: { type: string }
      required: [street, city, region, country]
    AddressPatch:
      type: object
      properties:
        street: { type: string }
        city: { type: string }
        region: { type: string }
        country: { type: string }
    FiscalCalendar:
      type: object
      properties:
        code: { type: string, description: "Fiscal calendar code (e.g., gregorian, retail-454)." }
        start_month: { type: integer, minimum: 1, maximum: 12 }
        start_day: { type: integer, minimum: 1, maximum: 31 }
        week_start: { type: string, enum: [mon, tue, wed, thu, fri, sat, sun] }
      required: [code]
    SearchPlane:
      type: object
      description: Org-level search plane overrides.
      additionalProperties: false
      properties:
        pvm:
          type: string
          enum: [gsi, opensearch]
          description: PVM list text search plane (tokenized GSI default; OpenSearch optional).
    OrgSummary:
      type: object
      description: Organization snapshot (org_guid is not included; use orgcode+resolve to obtain org_guid).
      additionalProperties: true
      properties:
        orgcode: { type: string }
        status:
          type: string
          enum: [unverified, verified, parked, suspended, frozen, doomed]
        caption: { type: string }
        timezone: { type: string, description: "IANA timezone (e.g., America/Los_Angeles)." }
        fiscal_calendar: { $ref: '#/components/schemas/FiscalCalendar' }
        search_plane: { $ref: '#/components/schemas/SearchPlane' }
        cost_centre_guid: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    CostCentreSummary:
      type: object
      additionalProperties: true
      properties:
        cc_guid: { type: string }
        cccode: { type: string }
        caption: { type: string }
        status: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    FacilitySummary:
      type: object
      additionalProperties: true
      properties:
        code: { type: string }
        caption: { type: string }
        status: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    ZoneSummary:
      type: object
      additionalProperties: true
      properties:
        zone_guid: { type: string }
        code: { type: string }
        caption: { type: string }
        status: { type: string }
        logical_guid: { type: string }
        parent_zone_guid: { type: string }
        depth: { type: integer }
        ancestors:
          type: array
          items: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    OwnerSummary:
      type: object
      additionalProperties: true
      properties:
        user_guid: { type: string }
        create_owner: { type: boolean }
        primary_owner: { type: boolean }
        secondary_owner: { type: boolean }
        state: { type: string }
        assigned_session_guid: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    MemberSummary:
      type: object
      additionalProperties: true
      properties:
        user_guid: { type: string }
        state: { type: string }
        role_profile_id: { type: string }
        role_version: { type: string }
        grants: {}
        notes: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    MemberAssignmentSummary:
      type: object
      additionalProperties: true
      properties:
        user_guid: { type: string }
        logical_guid: { type: string }
        state: { type: string }
        role_profile_id: { type: string }
        role_version: { type: string }
        grants: {}
        notes: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    ServiceAccountAssignmentSummary:
      type: object
      additionalProperties: true
      properties:
        service_account_guid: { type: string }
        logical_guid: { type: string }
        state: { type: string }
        role_profile_id: { type: string }
        role_version: { type: string }
        grants: {}
        notes: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    MemberInviteSummary:
      type: object
      additionalProperties: true
      properties:
        org_guid: { type: string }
        invite_guid: { type: string }
        code: { type: string }
        caption: { type: string }
        status: { type: string }
        expires_at_utc: { type: [string, 'null'], format: date-time }
        invited_by_user_guid: { type: string }
        invitee_user_guid: { type: string }
        consumed_by_user_guid: { type: string }
        consumed_at_utc: { type: string, format: date-time }
        revoked_by_user_guid: { type: string }
        revoked_at_utc: { type: string, format: date-time }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    TeamSummary:
      type: object
      additionalProperties: true
      properties:
        team_guid: { type: string }
        logical_guid: { type: string }
        code: { type: string }
        caption: { type: string }
        status: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    TeamMemberSummary:
      type: object
      additionalProperties: true
      properties:
        team_guid: { type: string }
        user_guid: { type: string }
        state: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    TeamByMemberSummary:
      type: object
      additionalProperties: true
      properties:
        team_guid: { type: string }
        user_guid: { type: string }
        code: { type: string }
        caption: { type: string }
        status: { type: string }
        state: { type: string }
        logical_guid: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    SalesChannelSummary:
      type: object
      additionalProperties: true
      properties:
        channel_guid: { type: string }
        logical_guid: { type: string }
        channel_code: { type: string }
        market_code: { type: string }
        external_ids:
          type: array
          description: Optional external identifiers (opaque keys) for lookup/idempotency; values are canonicalized case-insensitively (and `shop_domain` values are canonicalized to hostname).
          maxItems: 10
          items: { $ref: '#/components/schemas/SalesChannelExternalId' }
        locale_codes:
          type: array
          items: { type: string }
        default_locale_code: { type: string }
        caption: { type: string }
        status: { type: string }
        config_s3_bucket: { type: string }
        config_s3_key: { type: string }
        config_s3_version_id: { type: string }
        config_etag: { type: string }
        config_size_bytes: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }
    OrgListData:
      type: object
      properties:
        orgs:
          type: array
          items: { $ref: '#/components/schemas/OrgSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [orgs]
    CostCentreListData:
      type: object
      properties:
        cost_centres:
          type: array
          items: { $ref: '#/components/schemas/CostCentreSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [cost_centres]
    FacilityListData:
      type: object
      properties:
        facilities:
          type: array
          items: { $ref: '#/components/schemas/FacilitySummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [facilities]
    ZoneListData:
      type: object
      properties:
        zones:
          type: array
          items: { $ref: '#/components/schemas/ZoneSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [zones]
    OwnerListData:
      type: object
      properties:
        owners:
          type: array
          items: { $ref: '#/components/schemas/OwnerSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [owners]
    MemberListData:
      type: object
      properties:
        members:
          type: array
          items: { $ref: '#/components/schemas/MemberSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [members]
    MemberAssignmentsData:
      type: object
      properties:
        assignments:
          type: array
          items: { $ref: '#/components/schemas/MemberAssignmentSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [assignments]
    ServiceAccountAssignmentsData:
      type: object
      properties:
        assignments:
          type: array
          items: { $ref: '#/components/schemas/ServiceAccountAssignmentSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [assignments]
    MemberInviteListData:
      type: object
      properties:
        invites:
          type: array
          items: { $ref: '#/components/schemas/MemberInviteSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [invites]
    TeamListData:
      type: object
      properties:
        teams:
          type: array
          items: { $ref: '#/components/schemas/TeamSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [teams]
    TeamMembersData:
      type: object
      properties:
        members:
          type: array
          items: { $ref: '#/components/schemas/TeamMemberSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [members]
    TeamByMemberData:
      type: object
      properties:
        teams:
          type: array
          items: { $ref: '#/components/schemas/TeamByMemberSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [teams]
    SalesChannelListData:
      type: object
      properties:
        sales_channels:
          type: array
          items: { $ref: '#/components/schemas/SalesChannelSummary' }
        next_token: { $ref: '#/components/schemas/NextToken' }
      required: [sales_channels]
    SalesChannelExternalId:
      type: object
      properties:
        kind:
          type: string
          enum: [shop_domain, external_store_id]
          description: |
            Identifier kind (canonical registry).
            - `shop_domain`: Store domain/host (canonicalized to hostname). Allowed for channel_code: `shopify`, `shopify_plus`, `g3nlegacyshopify`, `dtc_generic`.
            - `external_store_id`: Stable store identifier in the channel implementation (canonicalized case-insensitively). Allowed for all channel_code values.
        descriptor:
          type: string
          description: |
            Optional namespace/descriptor for `kind=external_store_id` to prevent value collisions without expanding the `kind` registry.
            - Must be lowercase `snake_case` (example: `shopify_shop_id`, `pos_location_id`).
            - Only allowed when `kind=external_store_id`.
        value:
          type: string
          description: |
            Identifier value.
            - For `shop_domain`, this is canonicalized to a hostname (scheme/path/port stripped).
            - Otherwise canonicalized case-insensitively.
      required: [kind, value]
      additionalProperties: false
    SalesChannelResolveData:
      allOf:
        - $ref: '#/components/schemas/SalesChannelSummary'
    ResolveOrgcodeData:
      type: object
      properties:
        org_guid: { type: string }
      required: [org_guid]
    ResolveFacilityData:
      type: object
      additionalProperties: true
      properties:
        guid: { type: string }
        org_guid: { type: string }
        code: { type: string }
        kind: { type: string, enum: [physical, legal, logical] }
        status: { type: string }
      required: [guid, org_guid, code, kind]
    ResolveZoneData:
      type: object
      additionalProperties: true
      properties:
        org_guid: { type: string }
        logical_guid: { type: string }
        zone_guid: { type: string }
        code: { type: string }
        status: { type: string }
      required: [org_guid, logical_guid, zone_guid, code]
    ResolveCostCentreData:
      type: object
      additionalProperties: true
      properties:
        org_guid: { type: string }
        cc_guid: { type: string }
        cccode: { type: string }
        status: { type: string }
      required: [org_guid, cc_guid, cccode]
    MemberResolveData:
      type: object
      properties:
        org_guid: { type: string }
        orgcode: { type: string }
        org_status:
          type: string
          enum: [unverified, verified, parked, suspended, frozen, doomed]
          description: Organization status (tenant reads/writes blocked when not `verified`; `frozen` is operator-only freeze for offboarding).
        search_plane:
          $ref: '#/components/schemas/SearchPlane'
        user_guid: { type: string }
        is_owner: { type: boolean }
        member_state:
          type: string
          description: Member state when a member record exists (owners may be associated even if this is omitted).
        role_profile_id:
          type: string
          description: Optional org-level role profile identifier (opaque; treated as an effective role when in-window).
        grants:
          type: array
          description: Optional org-level grants (string identifiers) that are treated as effective roles when in-window.
          items: { type: string }
        roles:
          type: array
          description: Org-scoped effective roles. Includes `owner` when `is_owner=true`, plus `role_profile_id` and `grants[]` when the org member record is currently effective (state + effective_from/to).
          items: { type: string }
        logical_guid:
          type: string
          description: Optional logical facility scope for facility-scoped authorization decisions.
        logical_status:
          type: string
          description: Logical facility status when `logical_guid` is provided.
        logical_access:
          type: boolean
          description: When `logical_guid` is provided, whether the caller has facility-scoped access (owner implicit; members require explicit assignment).
        logical_roles:
          type: array
          description: Facility-scoped roles derived from the member↔logical assignment (or `["owner"]` for owners) when `logical_guid` is provided. These are not implicitly merged into `roles[]`.
          items: { type: string }
        logical_assignment_state:
          type: string
          description: Member↔logical assignment state when present.
        logical_assignment_effective:
          type: boolean
          description: Whether the member↔logical assignment is currently effective (state + effective_from/to).
      required: [org_guid, user_guid, is_owner, roles]

    OrgCreateData:
      type: object
      properties:
        org_guid: { type: string }
        orgcode: { type: string }
        status:
          type: string
          enum: [unverified, verified, parked, suspended, frozen, doomed]
        timezone: { type: string }
        fiscal_calendar: { $ref: '#/components/schemas/FiscalCalendar' }
        invitation:
          type: object
          additionalProperties: true
          properties:
            code: { type: string }
            referral_code: { type: string }
            schedule: {}
        owners:
          type: object
          additionalProperties: true
          properties:
            create_owner_user_guid: { type: string }
            primary_owner_user_guid: { type: string }
        cost_centre:
          type: object
          additionalProperties: true
          properties:
            cc_guid: { type: string }
            cccode: { type: string }
          required: [cc_guid, cccode]
      required: [org_guid, orgcode, status, cost_centre]
      example:
        org_guid: "00000000-0000-0000-0000-000000000000"
        orgcode: "ACME"
        status: "unverified"
        invitation: { code: "INV123456" }
        owners: { create_owner_user_guid: "11111111-1111-1111-1111-111111111111", primary_owner_user_guid: "11111111-1111-1111-1111-111111111111" }
        cost_centre: { cc_guid: "22222222-2222-2222-2222-222222222222", cccode: "ABCD-EFGH-IJKL" }

    OrgGetData:
      allOf:
        - $ref: '#/components/schemas/OrgSummary'
        - type: object
          properties:
            cost_centre:
              anyOf:
                - $ref: '#/components/schemas/CostCentreSummary'
                - type: 'null'
      example:
        orgcode: "ACME"
        status: "verified"
        caption: "Acme Inc"
        timezone: "America/Los_Angeles"
        fiscal_calendar: { code: "retail-454", start_month: 2, start_day: 1, week_start: "sun" }
        cost_centre_guid: "22222222-2222-2222-2222-222222222222"
        cost_centre: { cc_guid: "22222222-2222-2222-2222-222222222222", cccode: "ABCD-EFGH-IJKL", caption: "Master cost centre", status: "active" }

    OrgUpdateData:
      type: object
      properties:
        org_guid: { type: string }
        revision: { type: string }
      required: [org_guid, revision]

    OrgStatusSetData:
      type: object
      properties:
        org_guid: { type: string }
        status:
          type: string
          enum: [unverified, verified, parked, suspended, frozen, doomed]
        revision: { type: string }
      required: [org_guid, status, revision]

    CostCentreCreateData:
      type: object
      properties:
        org_guid: { type: string }
        cc_guid: { type: string }
        cccode: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [org_guid, cc_guid, cccode, status, revision]

    CostCentreUpdateData:
      type: object
      properties:
        org_guid: { type: string }
        cc_guid: { type: string }
        caption: { type: string }
        revision: { type: string }
      required: [org_guid, cc_guid, revision]

    CostCentreStatusSetData:
      type: object
      properties:
        org_guid: { type: string }
        cc_guid: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [org_guid, cc_guid, status, revision]

    FacilityPhysicalCreateData:
      type: object
      properties:
        pf_guid: { type: string }
        code: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [pf_guid, code, status, revision]
      example:
        pf_guid: "33333333-3333-3333-3333-333333333333"
        code: "PH_MAIN"
        status: "active"
        revision: "44444444-4444-4444-4444-444444444444"

    FacilityPhysicalGetData:
      type: object
      additionalProperties: true
      properties:
        code: { type: string }
        caption: { type: string }
        status: { type: string }
        address: { $ref: '#/components/schemas/Address' }
        phone: { type: string }
        fax: { type: string }
        email: { type: string }
        primary_contact: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }

    FacilityPhysicalUpdateData:
      type: object
      properties:
        org_guid: { type: string }
        pf_guid: { type: string }
        revision: { type: string }
      required: [org_guid, pf_guid, revision]

    FacilityPhysicalStatusData:
      type: object
      properties:
        org_guid: { type: string }
        pf_guid: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [org_guid, pf_guid, status, revision]

    FacilityLegalCreateData:
      type: object
      properties:
        legal_guid: { type: string }
        code: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [legal_guid, code, status, revision]

    FacilityLegalUpdateData:
      type: object
      properties:
        org_guid: { type: string }
        legal_guid: { type: string }
        revision: { type: string }
      required: [org_guid, legal_guid, revision]

    FacilityLegalStatusData:
      type: object
      properties:
        org_guid: { type: string }
        legal_guid: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [org_guid, legal_guid, status, revision]

    FacilityLogicalCreateData:
      type: object
      properties:
        logical_guid: { type: string }
        code: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [logical_guid, code, status, revision]

    FacilityLogicalGetData:
      type: object
      additionalProperties: true
      properties:
        code: { type: string }
        caption: { type: string }
        status: { type: string }
        physical_guid: { type: string }
        legal_guid: { type: string }
        cost_centre_guid: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: string }

    FacilityLogicalUpdateData:
      type: object
      properties:
        org_guid: { type: string }
        logical_guid: { type: string }
        revision: { type: string }
      required: [org_guid, logical_guid, revision]

    FacilityLogicalStatusData:
      type: object
      properties:
        org_guid: { type: string }
        logical_guid: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [org_guid, logical_guid, status, revision]

    ZoneCreateData:
      type: object
      properties:
        zone_guid: { type: string }
        code: { type: string }
        status: { type: string }
        depth: { type: integer }
        revision: { type: string }
      required: [zone_guid, code, status, depth, revision]
      example:
        zone_guid: "55555555-5555-5555-5555-555555555555"
        code: "AISLE_1"
        status: "active"
        depth: 2
        revision: "66666666-6666-6666-6666-666666666666"

    ZoneStatusData:
      type: object
      properties:
        org_guid: { type: string }
        logical_guid: { type: string }
        zone_guid: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [org_guid, logical_guid, zone_guid, status, revision]

    OwnerPrimarySetData:
      type: object
      properties:
        org_guid: { type: string }
        user_guid: { type: string }
        primary_owner: { type: boolean }
        revision: { type: string }
      required: [org_guid, user_guid, primary_owner, revision]

    OwnerSecondaryData:
      type: object
      properties:
        org_guid: { type: string }
        user_guid: { type: string }
        secondary_owner: { type: boolean }
        revision: { type: string }
      required: [org_guid, user_guid, secondary_owner, revision]

    OwnerStateSetData:
      type: object
      properties:
        org_guid: { type: string }
        user_guid: { type: string }
        state: { type: string }
        revision: { type: string }
      required: [org_guid, user_guid, state, revision]

    MemberInviteCreateData:
      type: object
      properties:
        org_guid: { type: string }
        invite_guid: { type: string }
        code: { type: string }
        status: { type: string }
        expires_at_utc: { type: [string, 'null'], format: date-time }
        revision: { type: string }
      required: [org_guid, invite_guid, code, status, revision]

    MemberInviteAcceptData:
      type: object
      properties:
        org_guid: { type: string }
        user_guid: { type: string }
        state: { type: string }
        revision: { type: string }
      required: [org_guid, user_guid, state, revision]
    MemberInviteRevokeData:
      type: object
      properties:
        org_guid: { type: string }
        invite_guid: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [org_guid, invite_guid, status, revision]

    MemberStateSetData:
      type: object
      properties:
        org_guid: { type: string }
        user_guid: { type: string }
        state: { type: string }
        revision: { type: string }
      required: [org_guid, user_guid, state, revision]

    MemberAssignLogicalData:
      type: object
      properties:
        org_guid: { type: string }
        user_guid: { type: string }
        logical_guid: { type: string }
        state: { type: string }
        revision: { type: string }
      required: [org_guid, user_guid, logical_guid, state, revision]

    MemberDetachLogicalData:
      type: object
      properties:
        org_guid: { type: string }
        user_guid: { type: string }
        logical_guid: { type: string }
        detached: { type: boolean }
      required: [org_guid, user_guid, logical_guid, detached]

    ServiceAccountAssignLogicalData:
      type: object
      properties:
        org_guid: { type: string }
        service_account_guid: { type: string }
        logical_guid: { type: string }
        state: { type: string }
        revision: { type: string }
      required: [org_guid, service_account_guid, logical_guid, state, revision]

    ServiceAccountDetachLogicalData:
      type: object
      properties:
        org_guid: { type: string }
        service_account_guid: { type: string }
        logical_guid: { type: string }
        detached: { type: boolean }
      required: [org_guid, service_account_guid, logical_guid, detached]

    TeamCreateData:
      type: object
      properties:
        org_guid: { type: string }
        team_guid: { type: string }
        code: { type: string }
        logical_guid: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [org_guid, team_guid, status, revision]

    TeamUpdateData:
      type: object
      properties:
        org_guid: { type: string }
        team_guid: { type: string }
        code: { type: string }
        caption: { type: string }
        logical_guid: { type: string }
        revision: { type: string }
      required: [org_guid, team_guid, revision]

    TeamStatusData:
      type: object
      properties:
        org_guid: { type: string }
        team_guid: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [org_guid, team_guid, status, revision]

    TeamMemberAddData:
      type: object
      properties:
        org_guid: { type: string }
        team_guid: { type: string }
        user_guid: { type: string }
        state: { type: string }
        revision: { type: string }
      required: [org_guid, team_guid, user_guid, state, revision]

    TeamMemberRemoveData:
      type: object
      properties:
        org_guid: { type: string }
        team_guid: { type: string }
        user_guid: { type: string }
        removed: { type: boolean }
      required: [org_guid, team_guid, user_guid, removed]

    SalesChannelCreateData:
      type: object
      properties:
        org_guid: { type: string }
        channel_guid: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [org_guid, channel_guid, status, revision]
      example:
        org_guid: "00000000-0000-0000-0000-000000000000"
        channel_guid: "77777777-7777-7777-7777-777777777777"
        status: "draft"
        revision: "88888888-8888-8888-8888-888888888888"

    SalesChannelUpdateData:
      type: object
      properties:
        org_guid: { type: string }
        channel_guid: { type: string }
        revision: { type: string }
      required: [org_guid, channel_guid, revision]

    SalesChannelStatusData:
      type: object
      properties:
        org_guid: { type: string }
        channel_guid: { type: string }
        status: { type: string }
        revision: { type: string }
      required: [org_guid, channel_guid, status, revision]

    PresignUpload:
      type: object
      properties:
        upload_url: { type: string }
        method: { type: string }
        headers:
          type: object
          additionalProperties: true
        expires_at: { type: string, format: date-time }
      required: [upload_url, method, headers, expires_at]

    SalesChannelConfigPresignData:
      type: object
      properties:
        org_guid: { type: string }
        channel_guid: { type: string }
        expected_revision: { type: string }
        presign: { $ref: '#/components/schemas/PresignUpload' }
        config_s3_bucket: { type: string }
        config_s3_key: { type: string }
      required: [org_guid, channel_guid, expected_revision, presign, config_s3_bucket, config_s3_key]
      example:
        org_guid: "00000000-0000-0000-0000-000000000000"
        channel_guid: "77777777-7777-7777-7777-777777777777"
        expected_revision: "88888888-8888-8888-8888-888888888888"
        presign:
          upload_url: "https://example.com/presigned-upload"
          method: "PUT"
          headers: { "Content-Type": "application/json" }
          expires_at: "2026-01-01T00:00:00Z"
        config_s3_bucket: "ofm-sales-channel-config"
        config_s3_key: "sales-channel-config/orgcode=ACME/channel_guid=77777777-7777-7777-7777-777777777777/config/1700000000000-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa.json"

    SalesChannelConfigPointer:
      type: object
      properties:
        config_s3_bucket: { type: string }
        config_s3_key: { type: string }
        config_s3_version_id: { type: string }
        config_etag: { type: string }
        config_size_bytes: { type: integer }
      required: [config_s3_bucket, config_s3_key, config_s3_version_id, config_etag, config_size_bytes]
      example:
        config_s3_bucket: "ofm-sales-channel-config"
        config_s3_key: "sales-channel-config/orgcode=ACME/channel_guid=77777777-7777-7777-7777-777777777777/config/1700000000000-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa.json"
        config_s3_version_id: "3HL4kqtJlcpXrof3y7Yv9ZVY0fFeiF6o"
        config_etag: "9e107d9d372bb6826bd81d3542a419d6"
        config_size_bytes: 1234

    SalesChannelConfigCompleteData:
      type: object
      properties:
        org_guid: { type: string }
        channel_guid: { type: string }
        config: { $ref: '#/components/schemas/SalesChannelConfigPointer' }
        revision: { type: string }
      required: [org_guid, channel_guid, config, revision]
      example:
        org_guid: "00000000-0000-0000-0000-000000000000"
        channel_guid: "77777777-7777-7777-7777-777777777777"
        config:
          config_s3_bucket: "ofm-sales-channel-config"
          config_s3_key: "sales-channel-config/orgcode=ACME/channel_guid=77777777-7777-7777-7777-777777777777/config/1700000000000-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa.json"
          config_s3_version_id: "3HL4kqtJlcpXrof3y7Yv9ZVY0fFeiF6o"
          config_etag: "9e107d9d372bb6826bd81d3542a419d6"
          config_size_bytes: 1234
        revision: "99999999-9999-9999-9999-999999999999"

paths:
  /stat:
    get:
      summary: Health check (session required)
      description: |
        Health check. Requires valid session_guid or api_key. Returns service name and status.
      x-route-class: Tier A
      x-qps-target: 5
      x-concurrency-target: 2
      x-latency-p95-ms: 500
      responses:
        '200':
          description: ok
        '401':
          description: Unauthorized — session_guid or api_key required
  /org/create:
    post:
      tags: [Organizations]
      operationId: orgCreate
      summary: Create Org
      description: |
        Create Org. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    orgcode: { type: string, description: Unique org code (human-facing) }
                    invitation_code: { type: string }
                    user_guid: { type: string }
                    caption: { type: string }
                    timezone: { type: string }
                    fiscal_calendar: { $ref: '#/components/schemas/FiscalCalendar' }
                  required: [orgcode, invitation_code, user_guid]
            examples:
              create:
                value:
                  session_guid: "00000000000000000000000000000000"
                  orgcode: "ACME"
                  invitation_code: "INV123456"
                  user_guid: "11111111-1111-1111-1111-111111111111"
                  caption: "Acme Inc"
                  timezone: "America/Los_Angeles"
                  fiscal_calendar: { code: "retail-454", start_month: 2, start_day: 1, week_start: "sun" }
      responses:
        '200':
          description: Organization created (includes default cost centre)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/OrgCreateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /org/get:
    post:
      tags: [Organizations]
      operationId: orgGet
      summary: Get Org
      description: |
        Get Org. Auth is via headers; org identity lives in the JSON body (org_guid).
        Org-scoped reads may return 404 for non-associated callers (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties: { org_guid: { type: string } }
                  required: [org_guid]
      responses:
        '200':
          description: Organization snapshot
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/OrgGetData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /org/list:
    post:
      tags: [Organizations]
      operationId: orgList
      summary: List Org
      description: |
        List Org. Auth is via headers; org identity lives in the JSON body (org_guid/orgcode/logical_guid).
        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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    status: { type: string, enum: [unverified, verified, parked, suspended, frozen, doomed] }
      responses:
        '200':
          description: List organizations associated with the session user
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/OrgListData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /org/update:
    post:
      tags: [Organizations]
      operationId: orgUpdate
      summary: Update Org
      description: |
        Update Org. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    caption: { type: string }
                    timezone: { type: string, nullable: true }
                    fiscal_calendar:
                      anyOf:
                        - $ref: '#/components/schemas/FiscalCalendar'
                        - type: 'null'
                    search_plane:
                      anyOf:
                        - $ref: '#/components/schemas/SearchPlane'
                        - type: 'null'
                  required: [org_guid, expected_revision]
      responses:
        '200':
          description: Organization updated
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/OrgUpdateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /org/status/set:
    post:
      tags: [Organizations]
      operationId: orgStatusSet
      summary: Set Org Status
      description: |
        Set Org Status. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    status: { type: string }
                    reason_code: { type: string }
                  required: [org_guid, expected_revision, status]
      responses:
        '200':
          description: Organization status updated (FSM enforced)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/OrgStatusSetData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /cost-centre/create:
    post:
      tags: [CostCentres]
      operationId: costCentreCreate
      summary: Create Cost Centre
      description: |
        Create Cost Centre. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    caption: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: Cost centre created
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/CostCentreCreateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /cost-centre/get:
    post:
      tags: [CostCentres]
      operationId: costCentreGet
      summary: Get Cost Centre
      description: |
        Get Cost Centre. Auth is via headers; org identity lives in the JSON body (org_guid + cc_guid).
        Org-scoped reads may return 404 for non-associated callers (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    cc_guid: { type: string }
                  required: [org_guid, cc_guid]
      responses:
        '200':
          description: Cost centre snapshot (anti-enumeration via 404)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/CostCentreSummary' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /cost-centre/list:
    post:
      tags: [CostCentres]
      operationId: costCentreList
      summary: List Cost Centre
      description: |
        List Cost Centre. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    status: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: List cost centres
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/CostCentreListData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /cost-centre/update:
    post:
      tags: [CostCentres]
      operationId: costCentreUpdate
      summary: Update Cost Centre
      description: |
        Update Cost Centre. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    cc_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    caption: { type: string }
                  required: [org_guid, cc_guid, expected_revision]
      responses:
        '200':
          description: Cost centre updated
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/CostCentreUpdateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /cost-centre/status/set:
    post:
      tags: [CostCentres]
      operationId: costCentreStatusSet
      summary: Set Cost Centre Status
      description: |
        Set Cost Centre Status. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    cc_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    status: { type: string }
                  required: [org_guid, cc_guid, expected_revision, status]
      responses:
        '200':
          description: Cost centre status updated (FSM enforced)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/CostCentreStatusSetData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /facility/physical/create:
    post:
      tags: [Facilities]
      operationId: facilityPhysicalCreate
      summary: Create Facility Physical
      description: |
        Create Facility Physical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    code: { type: string }
                    caption: { type: string }
                    address: { $ref: '#/components/schemas/Address' }
                    phone: { type: string }
                    fax: { type: string }
                    email: { type: string }
                    primary_contact: { type: string }
                  required: [org_guid, code, address, phone]
            examples:
              create:
                value:
                  session_guid: "00000000000000000000000000000000"
                  org_guid: "00000000-0000-0000-0000-000000000000"
                  code: "PH_MAIN"
                  caption: "Main store"
                  address: { street: "1 Main St", city: "Testville", region: "CA", country: "US" }
                  phone: "+10000000000"
      responses:
        '200':
          description: Physical facility created
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityPhysicalCreateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/physical/get:
    post:
      tags: [Facilities]
      operationId: facilityPhysicalGet
      summary: Get Facility Physical
      description: |
        Get Facility Physical. Auth is via headers; org identity lives in the JSON body (org_guid + pf_guid).
        Org-scoped reads may return 404 for non-associated callers (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    pf_guid: { type: string }
                  required: [org_guid, pf_guid]
            examples:
              by_guid:
                value:
                  session_guid: "00000000000000000000000000000000"
                  org_guid: "00000000-0000-0000-0000-000000000000"
                  pf_guid: "00000000-0000-0000-0000-000000000000"
              by_code:
                value:
                  session_guid: "00000000000000000000000000000000"
                  org_guid: "00000000-0000-0000-0000-000000000000"
                  code: "PH_MAIN"
      responses:
        '200':
          description: Physical facility snapshot
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityPhysicalGetData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/physical/list:
    post:
      tags: [Facilities]
      operationId: facilityPhysicalList
      summary: List Facility Physical
      description: |
        List Facility Physical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    status: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: List physical facilities
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityListData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/physical/update:
    post:
      tags: [Facilities]
      operationId: facilityPhysicalUpdate
      summary: Update Facility Physical
      description: |
        Update Facility Physical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    pf_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    caption: { type: string }
                    address: { $ref: '#/components/schemas/AddressPatch' }
                    phone: { type: string }
                    fax: { type: string }
                    email: { type: string }
                    primary_contact: { type: string }
                  required: [org_guid, pf_guid, expected_revision]
      responses:
        '200':
          description: Physical facility updated
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityPhysicalUpdateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/physical/status:
    post:
      tags: [Facilities]
      operationId: facilityPhysicalStatus
      summary: Status Facility Physical
      description: |
        Status Facility Physical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    pf_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    status: { type: string }
                  required: [org_guid, pf_guid, expected_revision, status]
      responses:
        '200':
          description: Physical facility status updated (FSM enforced)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityPhysicalStatusData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /facility/legal/create:
    post:
      tags: [Facilities]
      operationId: facilityLegalCreate
      summary: Create Facility Legal
      description: |
        Create Facility Legal. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    code: { type: string }
                    caption: { type: string }
                  required: [org_guid, code]
      responses:
        '200':
          description: Legal facility created
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityLegalCreateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/legal/get:
    post:
      tags: [Facilities]
      operationId: facilityLegalGet
      summary: Get Facility Legal
      description: |
        Get Facility Legal. Auth is via headers; org identity lives in the JSON body (org_guid + legal_guid).
        Org-scoped reads may return 404 for non-associated callers (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    legal_guid: { type: string }
                  required: [org_guid, legal_guid]
      responses:
        '200':
          description: Legal facility snapshot
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilitySummary' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/legal/list:
    post:
      tags: [Facilities]
      operationId: facilityLegalList
      summary: List Facility Legal
      description: |
        List Facility Legal. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    status: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: List legal facilities
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityListData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/legal/update:
    post:
      tags: [Facilities]
      operationId: facilityLegalUpdate
      summary: Update Facility Legal
      description: |
        Update Facility Legal. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    legal_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    caption: { type: string }
                  required: [org_guid, legal_guid, expected_revision]
      responses:
        '200':
          description: Legal facility updated
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityLegalUpdateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/legal/status:
    post:
      tags: [Facilities]
      operationId: facilityLegalStatus
      summary: Status Facility Legal
      description: |
        Status Facility Legal. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    legal_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    status: { type: string }
                  required: [org_guid, legal_guid, expected_revision, status]
      responses:
        '200':
          description: Legal facility status updated (FSM enforced)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityLegalStatusData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /facility/logical/create:
    post:
      tags: [Facilities]
      operationId: facilityLogicalCreate
      summary: Create Facility Logical
      description: |
        Create Facility Logical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    code: { type: string }
                    caption: { type: string }
                    physical_guid: { type: string }
                    legal_guid: { type: string }
                    cost_centre_guid: { type: string }
                  required: [org_guid, code, physical_guid, legal_guid]
      responses:
        '200':
          description: Logical facility created
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityLogicalCreateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/logical/get:
    post:
      tags: [Facilities]
      operationId: facilityLogicalGet
      summary: Get Facility Logical
      description: |
        Get Facility Logical. Auth is via headers; org identity lives in the JSON body (org_guid + logical_guid).
        Org-scoped reads may return 404 for non-associated callers (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                  required: [org_guid, logical_guid]
      responses:
        '200':
          description: Logical facility snapshot
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityLogicalGetData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/logical/list:
    post:
      tags: [Facilities]
      operationId: facilityLogicalList
      summary: List Facility Logical
      description: |
        List Facility Logical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    status: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: List logical facilities
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityListData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/logical/update:
    post:
      tags: [Facilities]
      operationId: facilityLogicalUpdate
      summary: Update Facility Logical
      description: |
        Update Facility Logical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    caption: { type: string }
                    cost_centre_guid: { type: string }
                  required: [org_guid, logical_guid, expected_revision]
      responses:
        '200':
          description: Logical facility updated
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityLogicalUpdateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /facility/logical/status:
    post:
      tags: [Facilities]
      operationId: facilityLogicalStatus
      summary: Status Facility Logical
      description: |
        Status Facility Logical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    status: { type: string }
                  required: [org_guid, logical_guid, expected_revision, status]
      responses:
        '200':
          description: Logical facility status updated (FSM enforced)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/FacilityLogicalStatusData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /zone/create:
    post:
      tags: [Zones]
      operationId: zoneCreate
      summary: Create Zone
      description: |
        Create Zone. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    parent_zone_guid: { type: string, description: Defaults to ROOT when omitted, default: "ROOT" }
                    code: { type: string }
                    caption: { type: string }
                  required: [org_guid, logical_guid, code]
      responses:
        '200':
          description: Zone created (hierarchy + depth constraints enforced; facility-granted members allowed)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/ZoneCreateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /zone/get:
    post:
      tags: [Zones]
      operationId: zoneGet
      summary: Get Zone
      description: |
        Get Zone. Auth is via headers; org identity lives in the JSON body (org_guid + logical_guid + zone_guid).
        Org-scoped reads may return 404 for non-associated callers (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    zone_guid: { type: string }
                  required: [org_guid, logical_guid, zone_guid]
      responses:
        '200':
          description: Zone snapshot (requires facility access)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/ZoneSummary' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /zone/list:
    post:
      tags: [Zones]
      operationId: zoneList
      summary: List Zone
      description: |
        List Zone. Auth is via headers; org identity lives in the JSON body (org_guid/orgcode/logical_guid).
        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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    parent_zone_guid: { type: string }
                  required: [org_guid, logical_guid]
      responses:
        '200':
          description: List zones (requires facility access; optionally filtered by parent_zone_guid)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/ZoneListData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /zone/status:
    post:
      tags: [Zones]
      operationId: zoneStatus
      summary: Status Zone
      description: |
        Status Zone. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    zone_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    status: { type: string }
                  required: [org_guid, logical_guid, zone_guid, expected_revision, status]
      responses:
        '200':
          description: Zone status updated (FSM enforced; members can toggle active↔inactive with facility grants; dooming requires owner)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/ZoneStatusData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /owner/list:
    post:
      tags: [Owners]
      operationId: ownerList
      summary: List Owner
      description: |
        List Owner. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: List owners
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/OwnerListData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /owner/primary/set:
    post:
      tags: [Owners]
      operationId: ownerPrimarySet
      summary: Set Owner Primary
      description: |
        Set Owner Primary. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    user_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                  required: [org_guid, user_guid, expected_revision]
      responses:
        '200':
          description: Set primary owner (org revision concurrency)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/OwnerPrimarySetData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /owner/secondary/add:
    post:
      tags: [Owners]
      operationId: ownerSecondaryAdd
      summary: Call Owner Secondary Add
      description: |
        Call Owner Secondary Add. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    user_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                  required: [org_guid, user_guid]
      responses:
        '200':
          description: Add secondary owner
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/OwnerSecondaryData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /owner/secondary/remove:
    post:
      tags: [Owners]
      operationId: ownerSecondaryRemove
      summary: Call Owner Secondary Remove
      description: |
        Call Owner Secondary Remove. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    user_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                  required: [org_guid, user_guid, expected_revision]
      responses:
        '200':
          description: Remove secondary owner
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/OwnerSecondaryData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /owner/state/set:
    post:
      tags: [Owners]
      operationId: ownerStateSet
      summary: Set Owner State
      description: |
        Set Owner State. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    user_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    state: { type: string }
                  required: [org_guid, user_guid, expected_revision, state]
      responses:
        '200':
          description: Owner state updated (FSM enforced)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/OwnerStateSetData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /member/invite/create:
    post:
      tags: [Members]
      operationId: memberInviteCreate
      summary: Create Member Invite
      description: |
        Create Member Invite. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    caption: { type: string }
                    invitee_user_guid: { type: string }
                    expires_at_utc: { type: string, format: date-time }
                    role_profile_id: { type: string }
                    role_version: { type: string }
                    grants:
                      type: array
                      items: { type: string }
                    effective_from: { type: string, format: date-time }
                    effective_to: { type: string, format: date-time }
                    notes: { type: string }
                    reason: { type: string }
                  required: [org_guid, invitee_user_guid]
      responses:
        '200':
          description: Member invite created (owner receives the invite code)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/MemberInviteCreateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /member/invite/accept:
    post:
      tags: [Members]
      operationId: memberInviteAccept
      summary: Call Member Invite Accept
      description: |
        Call Member Invite Accept. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    code: { type: string }
                    reason: { type: string }
                  required: [code]
      responses:
        '200':
          description: Member invite accepted (member record created)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/MemberInviteAcceptData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /member/invite/list:
    post:
      tags: [Members]
      operationId: memberInviteList
      summary: List Member Invite
      description: |
        List Member Invite. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    status: { type: string, description: 'Filter by status (e.g., active|consumed|doomed)' }
                  required: [org_guid]
      responses:
        '200':
          description: List member invites (owner-only)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/MemberInviteListData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /member/invite/revoke:
    post:
      tags: [Members]
      operationId: memberInviteRevoke
      summary: Revoke Member Invite
      description: |
        Revoke Member Invite. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    invite_guid: { type: string }
                    code: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    reason: { type: string }
                  required: [org_guid, expected_revision]
                - anyOf:
                    - type: object
                      properties:
                        invite_guid: { type: string }
                      required: [invite_guid]
                    - type: object
                      properties:
                        code: { type: string }
                      required: [code]
      responses:
        '200':
          description: Revoke member invite (active → doomed; owner-only)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/MemberInviteRevokeData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /member/state/set:
    post:
      tags: [Members]
      operationId: memberStateSet
      summary: Set Member State
      description: |
        Set Member State. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    user_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    state: { type: string }
                  required: [org_guid, user_guid, expected_revision, state]
      responses:
        '200':
          description: Member state updated (doomed is terminal)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/MemberStateSetData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /member/assign-logical:
    post:
      tags: [Members]
      operationId: memberAssignLogical
      summary: Call Member Assign Logical
      description: |
        Call Member Assign Logical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    user_guid: { type: string }
                    logical_guid: { type: string }
                    state: { type: string }
                    role_profile_id: { type: string }
                    role_version: { type: string }
                    grants: {}
                    effective_from: { type: string, format: date-time }
                    effective_to: { type: string, format: date-time }
                    notes: { type: string }
                  required: [org_guid, user_guid, logical_guid]
      responses:
        '200':
          description: Assign member to a logical facility (creates member↔logical edge)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/MemberAssignLogicalData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /member/detach-logical:
    post:
      tags: [Members]
      operationId: memberDetachLogical
      summary: Call Member Detach Logical
      description: |
        Call Member Detach Logical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    user_guid: { type: string }
                    logical_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                  required: [org_guid, user_guid, logical_guid, expected_revision]
      responses:
        '200':
          description: Detach member from a logical facility
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/MemberDetachLogicalData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /service-account/assign-logical:
    post:
      tags: [Service Accounts]
      operationId: serviceAccountAssignLogical
      summary: Call Service Account Assign Logical
      description: |
        Call Service Account Assign Logical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    service_account_guid: { type: string }
                    logical_guid: { type: string }
                    state: { type: string }
                    role_profile_id: { type: string }
                    role_version: { type: string }
                    grants: {}
                    effective_from: { type: string, format: date-time }
                    effective_to: { type: string, format: date-time }
                    notes: { type: string }
                  required: [org_guid, service_account_guid, logical_guid]
      responses:
        '200':
          description: Assign service account to a logical facility (creates service-account↔logical edge)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/ServiceAccountAssignLogicalData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /service-account/detach-logical:
    post:
      tags: [Service Accounts]
      operationId: serviceAccountDetachLogical
      summary: Call Service Account Detach Logical
      description: |
        Call Service Account Detach Logical. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    service_account_guid: { type: string }
                    logical_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                  required: [org_guid, service_account_guid, logical_guid, expected_revision]
      responses:
        '200':
          description: Detach service account from a logical facility
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/ServiceAccountDetachLogicalData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /service-account/assignments:
    post:
      tags: [Service Accounts]
      operationId: serviceAccountAssignments
      summary: Call Service Account Assignments
      description: |
        Call Service Account Assignments. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    service_account_guid: { type: string }
                  required: [org_guid, service_account_guid]
      responses:
        '200':
          description: List service-account↔logical assignment edges (owner-only)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/ServiceAccountAssignmentsData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /member/list:
    post:
      tags: [Members]
      operationId: memberList
      summary: List Member
      description: |
        List Member. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    state: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: List members
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/MemberListData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /member/names:
    post:
      tags: [Members]
      operationId: memberNames
      summary: Batch-resolve member display names
      description: |
        Returns user_guid → display_name for all members and owners in the org.
        Any authenticated org member can call this (not owner-only).
        Lightweight projection — returns only GUIDs and captions.
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: Member name map
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          names:
                            type: array
                            items:
                              type: object
                              properties:
                                user_guid: { type: string }
                                display_name: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /member/assignments:
    post:
      tags: [Members]
      operationId: memberAssignments
      summary: Call Member Assignments
      description: |
        Call Member Assignments. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    user_guid: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: List member logical assignments (self-mode when user_guid omitted)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/MemberAssignmentsData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /member/add:
    post:
      tags: [Members]
      operationId: memberAdd
      summary: Direct Add Member (owner-only)
      description: |
        Direct Add Member (owner-only). Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    logical_guid:
                      type: string
                      description: Optional logical facility scope for facility-scoped authorization decisions.
                - anyOf:
                    - type: object
                      properties:
                        org_guid: { type: string }
                      required: [org_guid]
                    - type: object
                      properties:
                        orgcode: { type: string }
                      required: [orgcode]
      responses:
        '200':
          description: Add member directly (owner-only)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { type: object }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /member/resolve:
    post:
      tags: [Members]
      operationId: memberResolve
      summary: Resolve Member
      description: |
        Resolve Member. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    logical_guid:
                      type: string
                      description: Optional logical facility scope for facility-scoped authorization decisions.
                - anyOf:
                    - type: object
                      properties:
                        org_guid: { type: string }
                      required: [org_guid]
                    - type: object
                      properties:
                        orgcode: { type: string }
                      required: [orgcode]
      responses:
        '200':
          description: Resolve caller membership/owner role for an org
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/MemberResolveData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /team/create:
    post:
      tags: [Teams]
      operationId: teamCreate
      summary: Create Team
      description: |
        Create Team. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string, description: Optional logical facility scope for the team }
                    code: { type: string }
                    caption: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: Team created (org-wide requires owner; logical-scoped allows facility-granted members)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/TeamCreateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /team/get:
    post:
      tags: [Teams]
      operationId: teamGet
      summary: Get Team
      description: |
        Get Team. Auth is via headers; org identity lives in the JSON body (org_guid + team_guid).
        Org-scoped reads may return 404 for non-associated callers (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    team_guid: { type: string }
                  required: [org_guid, team_guid]
      responses:
        '200':
          description: Team snapshot (org-wide requires owner; logical-scoped requires facility access + grants)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/TeamSummary' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /team/list:
    post:
      tags: [Teams]
      operationId: teamList
      summary: List Team
      description: |
        List Team. Auth is via headers; org identity lives in the JSON body (org_guid/orgcode/logical_guid).
        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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    status: { type: string }
                    logical_guid: { type: string, description: Optional logical facility scope filter }
                  required: [org_guid]
      responses:
        '200':
          description: List teams (org-wide list requires owner; logical-scoped list requires facility access + grants)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/TeamListData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /team/update:
    post:
      tags: [Teams]
      operationId: teamUpdate
      summary: Update Team
      description: |
        Update Team. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    team_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    caption: { type: string }
                    code: { type: string }
                    logical_guid: { type: [string, 'null'], description: Optional logical facility scope for the team; null clears }
                  required: [org_guid, team_guid, expected_revision]
      responses:
        '200':
          description: Team updated (org-wide requires owner; logical-scoped allows facility-granted members; dooming owner-only)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/TeamUpdateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /team/status:
    post:
      tags: [Teams]
      operationId: teamStatus
      summary: Status Team
      description: |
        Status Team. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    team_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    status: { type: string }
                  required: [org_guid, team_guid, expected_revision, status]
      responses:
        '200':
          description: Team status updated (FSM enforced; org-wide requires owner; logical-scoped allows facility-granted members; dooming owner-only)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/TeamStatusData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /team/member/add:
    post:
      tags: [Teams]
      operationId: teamMemberAdd
      summary: Call Team Member Add
      description: |
        Call Team Member Add. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    team_guid: { type: string }
                    user_guid: { type: string }
                    state: { type: string }
                  required: [org_guid, team_guid, user_guid]
      responses:
        '200':
          description: "Add team member (logical-scoped: added user must already have facility access; team membership never grants facility access)"
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/TeamMemberAddData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /team/member/remove:
    post:
      tags: [Teams]
      operationId: teamMemberRemove
      summary: Call Team Member Remove
      description: |
        Call Team Member Remove. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    team_guid: { type: string }
                    user_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                  required: [org_guid, team_guid, user_guid, expected_revision]
      responses:
        '200':
          description: Remove team member (org-wide requires owner; logical-scoped allows facility-granted members)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/TeamMemberRemoveData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /team/members:
    post:
      tags: [Teams]
      operationId: teamMembers
      summary: Call Team Members
      description: |
        Call Team Members. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    team_guid: { type: string }
                  required: [org_guid, team_guid]
      responses:
        '200':
          description: List team members (org-wide requires owner; logical-scoped allows facility-granted members)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/TeamMembersData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /team/by-member:
    post:
      tags: [Teams]
      operationId: teamByMember
      summary: Call Team By Member
      description: |
        Call Team By Member. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    user_guid: { type: string, description: Optional; defaults to session user when omitted }
                  required: [org_guid]
      responses:
        '200':
          description: List teams for a member (self allowed; other user requires owner)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/TeamByMemberData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /resolve/orgcode:
    post:
      tags: [Resolvers]
      operationId: resolveOrgcode
      summary: Call Resolve Orgcode
      description: |
        Call Resolve Orgcode. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    orgcode: { type: string }
                  required: [orgcode]
      responses:
        '200':
          description: Resolve orgcode to org_guid (anti-enumeration applies)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/ResolveOrgcodeData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /resolve/facility:
    post:
      tags: [Resolvers]
      operationId: resolveFacility
      summary: Call Resolve Facility
      description: |
        Call Resolve Facility. Owner-only. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    kind: { type: string, enum: [physical, legal, logical] }
                    code: { type: string }
                  required: [org_guid, kind, code]
      responses:
        '200':
          description: Resolve facility code to GUID
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/ResolveFacilityData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /resolve/zone:
    post:
      tags: [Resolvers]
      operationId: resolveZone
      summary: Call Resolve Zone
      description: |
        Call Resolve Zone. Requires facility grant for the logical (or owner). Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    logical_guid: { type: string }
                    code: { type: string }
                  required: [logical_guid, code]
      responses:
        '200':
          description: Resolve zone code to zone_guid
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/ResolveZoneData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /resolve/cost-centre:
    post:
      tags: [Resolvers]
      operationId: resolveCostCentre
      summary: Call Resolve Cost Centre
      description: |
        Call Resolve Cost Centre. Owner-only. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    cccode: { type: string }
                  required: [cccode]
      responses:
        '200':
          description: Resolve cccode to cc_guid
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/ResolveCostCentreData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }

  /sales-channel/create:
    post:
      tags: [SalesChannels]
      operationId: salesChannelCreate
      summary: Create Sales Channel
      description: |
        Create Sales Channel. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    channel_code: { type: string }
                    market_code: { type: string }
                    locale_codes:
                      type: array
                      items: { type: string }
                      minItems: 1
                    default_locale_code: { type: string }
                    external_ids:
                      type: array
                      maxItems: 10
                      items: { $ref: '#/components/schemas/SalesChannelExternalId' }
                    caption: { type: string }
                  required: [org_guid, logical_guid, channel_code, market_code, locale_codes]
                - anyOf:
                    # When multiple locale_codes are supplied, default_locale_code is required.
                    - type: object
                      properties:
                        locale_codes:
                          type: array
                          items: { type: string }
                          minItems: 1
                          maxItems: 1
                    - type: object
                      properties:
                        locale_codes:
                          type: array
                          items: { type: string }
                          minItems: 2
                        default_locale_code: { type: string }
                      required: [default_locale_code]
            examples:
              create_single_locale:
                value:
                  session_guid: "00000000000000000000000000000000"
                  org_guid: "00000000-0000-0000-0000-000000000000"
                  logical_guid: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
                  channel_code: "shopify"
                  market_code: "US"
                  locale_codes: ["en-US"]
                  external_ids: [{kind: "shop_domain", value: "example.myshopify.com"}]
                  caption: "Shopify US store"
              create_multi_locale:
                value:
                  session_guid: "00000000000000000000000000000000"
                  org_guid: "00000000-0000-0000-0000-000000000000"
                  logical_guid: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"
                  channel_code: "shopify_plus"
                  market_code: "CA"
                  locale_codes: ["en-CA", "fr-CA"]
                  default_locale_code: "en-CA"
                  caption: "Shopify Plus CA store"
      responses:
        '200':
          description: Sales channel declaration created (status=draft; facility-granted members allowed)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/SalesChannelCreateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /sales-channel/get:
    post:
      tags: [SalesChannels]
      operationId: salesChannelGet
      summary: Get Sales Channel
      description: |
        Get Sales Channel. Requires facility grant for the channel logical (or owner). Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    channel_guid: { type: string }
                  required: [org_guid, channel_guid]
      responses:
        '200':
          description: Sales channel declaration snapshot
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/SalesChannelSummary' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /sales-channel/list:
    post:
      tags: [SalesChannels]
      operationId: salesChannelList
      summary: List Sales Channel
      description: |
        List Sales Channel. Org-wide list is owner-only; when logical_guid is provided, requires facility grant
        for that logical (or owner). Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    status: { type: string }
                    channel_code: { type: string }
                    market_code: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: List sales channel declarations
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/SalesChannelListData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /sales-channel/update:
    post:
      tags: [SalesChannels]
      operationId: salesChannelUpdate
      summary: Update Sales Channel
      description: |
        Update Sales Channel. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    channel_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    caption: { type: string }
                    logical_guid: { type: string }
                    channel_code: { type: string }
                    market_code: { type: string }
                    locale_codes:
                      type: array
                      items: { type: string }
                      minItems: 1
                    default_locale_code: { type: string }
                    external_ids:
                      type: array
                      maxItems: 10
                      items: { $ref: '#/components/schemas/SalesChannelExternalId' }
                  required: [org_guid, channel_guid, expected_revision]
      responses:
        '200':
          description: Sales channel declaration updated (members can edit drafts + caption/config pointers with facility grants; activation remains owner-only)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/SalesChannelUpdateData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /sales-channel/status:
    post:
      tags: [SalesChannels]
      operationId: salesChannelStatus
      summary: Status Sales Channel
      description: |
        Status Sales Channel. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    channel_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    status: { type: string, enum: [draft, active, inactive, doomed] }
                  required: [org_guid, channel_guid, expected_revision, status]
      responses:
        '200':
          description: Sales channel declaration status updated (FSM enforced; owner-only)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/SalesChannelStatusData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /sales-channel/config/presign:
    post:
      tags: [SalesChannels]
      operationId: salesChannelConfigPresign
      summary: Call Sales Channel Config Presign
      description: |
        Call Sales Channel Config Presign. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    channel_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                  required: [org_guid, channel_guid, expected_revision]
            examples:
              presign:
                value:
                  session_guid: "00000000000000000000000000000000"
                  org_guid: "00000000-0000-0000-0000-000000000000"
                  channel_guid: "77777777-7777-7777-7777-777777777777"
                  expected_revision: "88888888-8888-8888-8888-888888888888"
      responses:
        '200':
          description: Presigned S3 upload URL for sales channel config JSON (facility-granted members allowed)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/SalesChannelConfigPresignData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /sales-channel/config/complete:
    post:
      tags: [SalesChannels]
      operationId: salesChannelConfigComplete
      summary: Call Sales Channel Config Complete
      description: |
        Call Sales Channel Config Complete. Auth is via headers; org identity lives in the JSON body
        (org_guid/orgcode/logical_guid). 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:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    channel_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    config_s3_key: { type: string }
                  required: [org_guid, channel_guid, expected_revision, config_s3_key]
            examples:
              complete:
                value:
                  session_guid: "00000000000000000000000000000000"
                  org_guid: "00000000-0000-0000-0000-000000000000"
                  channel_guid: "77777777-7777-7777-7777-777777777777"
                  expected_revision: "88888888-8888-8888-8888-888888888888"
                  config_s3_key: "sales-channel-config/orgcode=ACME/channel_guid=77777777-7777-7777-7777-777777777777/config/1700000000000-aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa.json"
      responses:
        '200':
          description: Complete config update (verifies object and stores pointer metadata; facility-granted members allowed)
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/SalesChannelConfigCompleteData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /sales-channel/resolve:
    post:
      tags: [SalesChannels]
      operationId: salesChannelResolve
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      description: |
        Resolve a sales channel declaration by external identifier. Requires facility grant for the channel logical (or owner).

        Behavior:
        - If an active binding exists for the external id, it is returned.
        - If no active binding exists, the call succeeds only when exactly one non-doomed channel matches; otherwise returns `409` with tag `ambiguous`.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    external_id_kind: { type: string, enum: [shop_domain, external_store_id] }
                    external_id_descriptor: { type: string }
                    external_id_value: { type: string }
                  required: [org_guid, external_id_kind, external_id_value]
            examples:
              resolve_by_domain:
                value:
                  session_guid: "00000000000000000000000000000000"
                  org_guid: "00000000-0000-0000-0000-000000000000"
                  external_id_kind: "shop_domain"
                  external_id_value: "example.myshopify.com"
              resolve_by_external_store_id:
                value:
                  session_guid: "00000000000000000000000000000000"
                  org_guid: "00000000-0000-0000-0000-000000000000"
                  external_id_kind: "external_store_id"
                  external_id_descriptor: "shopify_shop_id"
                  external_id_value: "123456789"
      responses:
        '200':
          description: Resolve sales channel by external identifier
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data: { $ref: '#/components/schemas/SalesChannelResolveData' }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /sales-channel/inventory-sources/set:
    post:
      tags: [SalesChannels]
      operationId: salesChannelInventorySourcesSet
      summary: Set Sales Channel Inventory Sources
      description: |
        Replace inventory source configuration for a sales channel. Owner-only.
        Sources define which logical facilities supply inventory (with priority) for this channel.
        Route class Tier D (p95 800ms).
      x-route-class: Tier D
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 800
      x-latency-p99-ms: 1200
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    channel_guid: { type: string }
                    sources:
                      type: array
                      items:
                        type: object
                        properties:
                          logical_guid: { type: string }
                          priority: { type: integer }
                          status: { type: string, enum: [active, inactive] }
                        required: [logical_guid, priority]
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    reason: { type: string }
                  required: [org_guid, channel_guid, sources, expected_revision]
      responses:
        '200':
          description: Inventory sources replaced
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          org_guid: { type: string }
                          channel_guid: { type: string }
                          sources: { type: array }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /sales-channel/inventory-sources/get:
    post:
      tags: [SalesChannels]
      operationId: salesChannelInventorySourcesGet
      summary: Get Sales Channel Inventory Sources
      description: |
        Retrieve inventory source configuration for a sales channel.
        Requires facility grant (read) on the channel's primary logical facility.
        Route class Tier C (p95 400ms).
      x-route-class: Tier C
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 400
      x-latency-p99-ms: 800
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    channel_guid: { type: string }
                  required: [org_guid, channel_guid]
      responses:
        '200':
          description: Inventory sources for the channel
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          org_guid: { type: string }
                          channel_guid: { type: string }
                          primary: { type: object, properties: { logical_guid: { type: string } } }
                          sources: { type: array }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /station/create:
    post:
      tags: [Stations]
      operationId: stationCreate
      summary: Create Station
      description: |
        Create a POS station within a logical facility. Requires facility:write or station:write grant.
        station_code must be unique within the logical facility. Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    station_code: { type: string }
                    station_type: { type: string, enum: [register, kiosk, mobile, self_checkout] }
                    channel_guid: { type: string }
                    caption: { type: string }
                    hardware_profile: { type: object }
                  required: [org_guid, logical_guid, station_code, station_type]
      responses:
        '200':
          description: Station created
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          station_guid: { type: string }
                          station_code: { type: string }
                          station_type: { type: string }
                          status: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /station/get:
    post:
      tags: [Stations]
      operationId: stationGet
      summary: Get Station
      description: |
        Get station by station_guid. Requires facility grant (read) on the station's logical facility.
        Route class Tier B (p95 300ms).
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    station_guid: { type: string }
                  required: [org_guid, station_guid]
      responses:
        '200':
          description: Station snapshot
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          station_guid: { type: string }
                          org_guid: { type: string }
                          logical_guid: { type: string }
                          station_code: { type: string }
                          station_type: { type: string }
                          channel_guid: { type: string }
                          caption: { type: string }
                          hardware_profile: { type: object }
                          status: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /station/list:
    post:
      tags: [Stations]
      operationId: stationList
      summary: List Stations
      description: |
        List stations within a logical facility. Requires facility grant (read).
        Optional status filter. Paginated with limit/next_token. Route class Tier B (p95 300ms).
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    status: { type: string, enum: [active, inactive, maintenance] }
                  required: [org_guid, logical_guid]
      responses:
        '200':
          description: Paginated station list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          items: { type: array }
                          next_token: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /station/update:
    post:
      tags: [Stations]
      operationId: stationUpdate
      summary: Update Station
      description: |
        Update mutable fields of a station (caption, station_type, channel_guid, hardware_profile).
        Immutable: station_code, logical_guid. Requires facility:write or station:write grant.
        expected_revision required. Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    station_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    caption: { type: string }
                    station_type: { type: string, enum: [register, kiosk, mobile, self_checkout] }
                    channel_guid: { type: string }
                    hardware_profile: { type: object }
                  required: [org_guid, station_guid, expected_revision]
      responses:
        '200':
          description: Station updated
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          org_guid: { type: string }
                          station_guid: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /station/status:
    post:
      tags: [Stations]
      operationId: stationStatus
      summary: Set Station Status
      description: |
        Transition station status. Allowed transitions: active <-> inactive, active <-> maintenance,
        inactive <-> maintenance. Requires facility:write or station:write grant.
        expected_revision required. Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    station_guid: { type: string }
                    status: { type: string, enum: [active, inactive, maintenance] }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    reason: { type: string }
                  required: [org_guid, station_guid, status, expected_revision]
      responses:
        '200':
          description: Station status updated
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          org_guid: { type: string }
                          station_guid: { type: string }
                          status: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /shift/create:
    post:
      tags: [Shifts]
      operationId: shiftCreate
      summary: Create Shift
      description: |
        Create a scheduled shift assigning a member to a logical facility for a role/position.
        Requires schedule:write grant. Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    user_guid: { type: string }
                    shift_date: { type: string, format: date, description: 'ISO date YYYY-MM-DD' }
                    start_time: { type: string, description: 'HH:MM 24h local' }
                    end_time: { type: string, description: 'HH:MM 24h local' }
                    timezone: { type: string, description: 'IANA timezone e.g. America/New_York' }
                    role_label: { type: string, description: 'Freeform role e.g. cashier, stylist' }
                    station_guid: { type: string }
                    notes: { type: string }
                  required: [org_guid, logical_guid, user_guid, shift_date, start_time, end_time, timezone, role_label]
      responses:
        '200':
          description: Shift created
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          shift_guid: { type: string }
                          shift_date: { type: string }
                          start_time: { type: string }
                          end_time: { type: string }
                          role_label: { type: string }
                          status: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /shift/get:
    post:
      tags: [Shifts]
      operationId: shiftGet
      summary: Get Shift
      description: |
        Get shift by shift_guid. Requires session + org association. Route class Tier B (p95 300ms).
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    shift_guid: { type: string }
                  required: [org_guid, shift_guid]
      responses:
        '200':
          description: Shift snapshot
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          shift_guid: { type: string }
                          org_guid: { type: string }
                          logical_guid: { type: string }
                          user_guid: { type: string }
                          shift_date: { type: string }
                          start_time: { type: string }
                          end_time: { type: string }
                          timezone: { type: string }
                          role_label: { type: string }
                          station_guid: { type: string }
                          notes: { type: string }
                          status: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /shift/list:
    post:
      tags: [Shifts]
      operationId: shiftList
      summary: List Shifts
      description: |
        List shifts by facility+date or member+date. Requires session + org association.
        Paginated with limit/next_token. Route class Tier B (p95 300ms).
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    user_guid: { type: string }
                    shift_date: { type: string }
                    from_date: { type: string }
                    to_date: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: Paginated shift list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          items: { type: array }
                          next_token: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /shift/update:
    post:
      tags: [Shifts]
      operationId: shiftUpdate
      summary: Update Shift
      description: |
        Update mutable fields of a shift (start_time, end_time, role_label, station_guid, notes, user_guid).
        Requires schedule:write grant. expected_revision required. Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    shift_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    start_time: { type: string }
                    end_time: { type: string }
                    role_label: { type: string }
                    station_guid: { type: string }
                    notes: { type: string }
                    user_guid: { type: string }
                  required: [org_guid, shift_guid, expected_revision]
      responses:
        '200':
          description: Shift updated
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          org_guid: { type: string }
                          shift_guid: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /shift/status:
    post:
      tags: [Shifts]
      operationId: shiftStatus
      summary: Set Shift Status
      description: |
        Transition shift status. Allowed: scheduled→active, scheduled→cancelled, active→completed, active→cancelled.
        Requires schedule:write grant. expected_revision required. Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    shift_guid: { type: string }
                    status: { type: string, enum: [scheduled, active, completed, cancelled] }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    reason: { type: string }
                  required: [org_guid, shift_guid, status, expected_revision]
      responses:
        '200':
          description: Shift status updated
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          org_guid: { type: string }
                          shift_guid: { type: string }
                          status: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /timesheet/clock-in:
    post:
      tags: [Timesheets]
      operationId: timesheetClockIn
      summary: Clock In
      description: |
        Start a timesheet entry (clock in) for a member at a facility. Only one open entry per member.
        Requires timesheet:write grant. Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    user_guid: { type: string }
                    shift_guid: { type: string }
                    notes: { type: string }
                  required: [org_guid, logical_guid, user_guid]
      responses:
        '200':
          description: Clocked in
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          entry_guid: { type: string }
                          clock_in: { type: string, format: date-time }
                          status: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /timesheet/clock-out:
    post:
      tags: [Timesheets]
      operationId: timesheetClockOut
      summary: Clock Out
      description: |
        Close an open timesheet entry (clock out). Computes duration_minutes. Requires timesheet:write grant.
        expected_revision required. Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    entry_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    break_minutes: { type: integer, minimum: 0 }
                    notes: { type: string }
                  required: [org_guid, entry_guid, expected_revision]
      responses:
        '200':
          description: Clocked out
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          entry_guid: { type: string }
                          clock_out: { type: string, format: date-time }
                          duration_minutes: { type: integer }
                          status: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /timesheet/get:
    post:
      tags: [Timesheets]
      operationId: timesheetGet
      summary: Get Timesheet Entry
      description: |
        Get timesheet entry by entry_guid. Requires session + org association. Route class Tier B (p95 300ms).
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    entry_guid: { type: string }
                  required: [org_guid, entry_guid]
      responses:
        '200':
          description: Timesheet entry snapshot
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          entry_guid: { type: string }
                          org_guid: { type: string }
                          logical_guid: { type: string }
                          user_guid: { type: string }
                          shift_guid: { type: string }
                          clock_in: { type: string, format: date-time }
                          clock_out: { type: string, format: date-time }
                          break_minutes: { type: integer }
                          duration_minutes: { type: integer }
                          notes: { type: string }
                          status: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /timesheet/list:
    post:
      tags: [Timesheets]
      operationId: timesheetList
      summary: List Timesheet Entries
      description: |
        List timesheet entries by facility+date range or member+date range. Requires session + org association.
        Paginated with limit/next_token. Route class Tier B (p95 300ms).
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - $ref: '#/components/schemas/PaginationRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    logical_guid: { type: string }
                    user_guid: { type: string }
                    from_date: { type: string }
                    to_date: { type: string }
                  required: [org_guid]
      responses:
        '200':
          description: Paginated timesheet entry list
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          items: { type: array }
                          next_token: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  /timesheet/void:
    post:
      tags: [Timesheets]
      operationId: timesheetVoid
      summary: Void Timesheet Entry
      description: |
        Void an open or closed timesheet entry (manager correction). Requires timesheet:write grant.
        expected_revision + reason required. Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody:
        required: true
        content:
          application/json:
            schema:
              allOf:
                - $ref: '#/components/schemas/SessionRequest'
                - type: object
                  properties:
                    org_guid: { type: string }
                    entry_guid: { type: string }
                    expected_revision: { $ref: '#/components/schemas/ExpectedRevision' }
                    reason: { type: string }
                  required: [org_guid, entry_guid, expected_revision, reason]
      responses:
        '200':
          description: Entry voided
          content:
            application/json:
              schema:
                allOf:
                  - $ref: '#/components/schemas/OkResponse'
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          entry_guid: { type: string }
                          status: { type: string }
                          revision: { type: string }
        default:
          description: Error
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ErrorResponse' }
  # POS Operator Profiles (T1-01)
  /profile/create:
    post:
      tags: [POS Profiles]
      operationId: profileCreate
      summary: Create POS Operator Profile
      description: Create a named profile with 30+ cashier controls (discount limits, tender restrictions, department gating, transaction controls, cash management). Requires owner.
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid, profile_code], properties: { org_guid: { type: string }, profile_code: { type: string }, caption: { type: string }, controls: { type: object } } }] } } } }
      responses: { '200': { description: Profile created, content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
  /profile/get:
    post:
      tags: [POS Profiles]
      operationId: profileGet
      summary: Get POS Operator Profile
      description: Fetch profile by ID.
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 300
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid, profile_id], properties: { org_guid: { type: string }, profile_id: { type: string } } }] } } } }
      responses: { '200': { description: Profile, content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
  /profile/list:
    post:
      tags: [POS Profiles]
      operationId: profileList
      summary: List POS Operator Profiles
      description: Paginated list by status (active/inactive/doomed).
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 300
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid], properties: { org_guid: { type: string }, status: { type: string }, limit: { type: integer }, next_token: { type: string } } }] } } } }
      responses: { '200': { description: Profile list, content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
  /profile/update:
    post:
      tags: [POS Profiles]
      operationId: profileUpdate
      summary: Update POS Operator Profile
      description: Partial merge of profile controls. Requires expected_revision.
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid, profile_id, expected_revision], properties: { org_guid: { type: string }, profile_id: { type: string }, expected_revision: { type: string }, caption: { type: string }, controls: { type: object } } }] } } } }
      responses: { '200': { description: Updated profile, content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
  /profile/status:
    post:
      tags: [POS Profiles]
      operationId: profileStatusSet
      summary: Set Profile Status
      description: Activate, deactivate, or doom a profile. FSM enforced.
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid, profile_id, status, expected_revision], properties: { org_guid: { type: string }, profile_id: { type: string }, status: { type: string, enum: [active, inactive, doomed] }, expected_revision: { type: string } } }] } } } }
      responses: { '200': { description: Status updated, content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
  /profile/assign:
    post:
      tags: [POS Profiles]
      operationId: profileAssign
      summary: Assign Profile
      description: Assign profile to member+facility, facility default, or org default. 3-level cascade.
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid, profile_id, level], properties: { org_guid: { type: string }, profile_id: { type: string }, level: { type: string, enum: [member, facility, org] }, member_guid: { type: string }, logical_guid: { type: string } } }] } } } }
      responses: { '200': { description: Assigned, content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
  /profile/unassign:
    post:
      tags: [POS Profiles]
      operationId: profileUnassign
      summary: Unassign Profile
      description: Remove member or facility assignment. Org default cannot be unassigned.
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid, level], properties: { org_guid: { type: string }, level: { type: string, enum: [member, facility] }, member_guid: { type: string }, logical_guid: { type: string } } }] } } } }
      responses: { '200': { description: Unassigned, content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
  /profile/resolve:
    post:
      tags: [POS Profiles]
      operationId: profileResolve
      summary: Resolve Effective Profile
      description: 3-level cascade (member→facility→org) to resolve effective profile for a member at a facility.
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 300
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid, logical_guid], properties: { org_guid: { type: string }, member_guid: { type: string }, logical_guid: { type: string } } }] } } } }
      responses: { '200': { description: Resolved profile, content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
  # Override Codes (T1-01)
  /override-code/generate:
    post:
      tags: [Override Codes]
      operationId: overrideCodeGenerate
      summary: Generate Override Code
      description: Generate 6-digit crypto-random code. Issuer profile validated — cannot exceed own limits.
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid, facility_guid, override_types], properties: { org_guid: { type: string }, facility_guid: { type: string }, override_types: { type: array, items: { type: object } }, usage_mode: { type: string, enum: [one_time, multi_use] }, max_uses: { type: integer }, expiry_minutes: { type: integer } } }] } } } }
      responses: { '200': { description: Code generated (plaintext returned once), content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
  /override-code/validate:
    post:
      tags: [Override Codes]
      operationId: overrideCodeValidate
      summary: Validate Override Code
      description: 7-step validation (exists, active, facility match, type match, limit check, usage check, expiry).
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 300
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid, code, facility_guid, override_type], properties: { org_guid: { type: string }, code: { type: string }, facility_guid: { type: string }, override_type: { type: string }, requested_value: { type: object } } }] } } } }
      responses: { '200': { description: Validation result, content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
  /override-code/revoke:
    post:
      tags: [Override Codes]
      operationId: overrideCodeRevoke
      summary: Revoke Override Code
      description: Immediately invalidate an active override code.
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      x-latency-p99-ms: 1000
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid, code_id], properties: { org_guid: { type: string }, code_id: { type: string }, reason: { type: string } } }] } } } }
      responses: { '200': { description: Revoked, content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
  /override-code/list:
    post:
      tags: [Override Codes]
      operationId: overrideCodeList
      summary: List Override Codes
      description: Paginated list with optional status and facility filters.
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 300
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      requestBody: { required: true, content: { application/json: { schema: { allOf: [{ $ref: '#/components/schemas/SessionRequest' }, { type: object, required: [org_guid], properties: { org_guid: { type: string }, status: { type: string }, facility_guid: { type: string }, limit: { type: integer }, next_token: { type: string } } }] } } } }
      responses: { '200': { description: Code list, content: { application/json: { schema: { $ref: '#/components/schemas/OkResponse' } } } }, default: { description: Error, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } }
