openapi: 3.1.0
info:
  title: CRM/Loyalty API
  version: 0.1.0-draft
  description: |
    Customer Relationship Management and Loyalty.

    Contract notes:
    - API Gateway base path: `/crm`
    - Org-gated: supply `x-orgcode`.
    - Facility/channel context is captured where relevant.
    - Request context is captured for auditability (org/facility/channel/roles/cost-centre).
    - Auth: either `x-session-guid` (user session) or `x-api-key` (org-bound service account).
      Headers are canonical; body `session_guid`/`api_key` accepted for compatibility on POST.
servers:
  - url: https://api.g3nretailstack.com/crm
security:
  - sessionAuth: []
  - apiKeyAuth: []
components:
  securitySchemes:
    sessionAuth:
      type: apiKey
      in: header
      name: x-session-guid
    apiKeyAuth:
      type: apiKey
      in: header
      name: x-api-key
  parameters:
    OrgHeader:
      in: header
      name: x-orgcode
      required: true
      schema: { type: string }
    LogicalHeader:
      in: header
      name: x-logical-guid
      required: false
      schema: { type: string }
    ChannelHeader:
      in: header
      name: x-channel-code
      required: false
      schema: { type: string }
  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: [crm] }
        request_id: { type: string }
        timestamp_utc: { type: string, format: date-time }
        actor: { type: string }
        context_source:
          type: string
          enum: [session, api_key, operator, system]
        session_fingerprint:
          type: string
          description: Non-reversible SHA-256 fingerprint of the caller session (`session_guid`) for correlation (never an auth credential).
        api_key_fingerprint:
          type: string
          description: Non-reversible SHA-256 fingerprint of the caller `api_key` for correlation (never an auth credential).
        orgcode: { type: string }
        cccode: { type: string }
        logical_guid: { type: string }
        channel_code: { type: string }
        roles:
          type: array
          items: { type: string }
        build:
          $ref: '#/components/schemas/BuildMeta'
      required: [call, service, timestamp_utc, build]
    Error:
      type: object
      properties:
        error_code: { type: string }
        http_status: { type: integer }
        retryable: { type: boolean }
        request_id: { type: string }
        trace_id: { type: string }
        major: { type: string }
        minor: { type: string }
        message: { type: string }
        details: { type: object }
    Envelope:
      type: object
      properties:
        success: { type: boolean }
        data: { type: object }
        error: { $ref: '#/components/schemas/Error' }
        stats: { $ref: '#/components/schemas/Stats' }
      required: [success]
    SourceRef:
      type: object
      properties:
        kind: { type: string }
        id: { type: string }
      required: [kind, id]
    SourceRefs:
      type: array
      items: { $ref: '#/components/schemas/SourceRef' }
    RequestContext:
      type: object
      properties:
        orgcode: { type: string }
        logical_guid: { type: string }
        channel_code: { type: string }
        cccode: { type: string }
        actor: { type: string }
        roles:
          type: array
          items: { type: string }
        context_source:
          type: string
          enum: [session, api_key, operator, system]
        session_fingerprint: { type: string }
        api_key_fingerprint: { type: string }
      required: [orgcode, actor, context_source]
      additionalProperties: false
    PolicyRefs:
      type: object
      properties:
        tax_policy_version: { type: string }
        pricing_policy_version: { type: string }
        promotion_policy_version: { type: string }
        discount_policy_version: { type: string }
        stacking_policy_version: { type: string }
        approval_policy_version: { type: string }
        tender_policy_version: { type: string }
        returns_policy_version: { type: string }
        fraud_policy_version: { type: string }
        loyalty_policy_version: { type: string }
        stored_value_policy_version: { type: string }
        earning_policy_version: { type: string }
        backorder_policy_version: { type: string }
        special_order_policy_version: { type: string }
        transfer_policy_version: { type: string }
        count_policy_version: { type: string }
        adjustment_policy_version: { type: string }
        po_policy_version: { type: string }
        matching_policy_version: { type: string }
        tolerance_policy_version: { type: string }
        receiving_policy_version: { type: string }
        qc_policy_version: { type: string }
        rtv_policy_version: { type: string }
        credit_policy_version: { type: string }
        shipping_policy_version: { type: string }
        export_policy_version: { type: string }
      additionalProperties: true
    Money:
      type: object
      properties:
        currency: { type: string }
        amount: { type: number }
      required: [currency, amount]
    ExternalRef:
      type: object
      properties:
        system: { type: string }
        external_id: { type: string }
      required: [system, external_id]
    LoyaltyBalance:
      type: object
      properties:
        available_points: { type: integer }
        pending_points: { type: integer }
        lifetime_earned: { type: integer }
        lifetime_redeemed: { type: integer }
        last_earned_at: { type: string, format: date-time }
        last_redeemed_at: { type: string, format: date-time }
        expiry_buckets:
          type: array
          items: { $ref: '#/components/schemas/LoyaltyExpiryBucket' }
    CustomerDraft:
      type: object
      properties:
        request_context: { $ref: '#/components/schemas/RequestContext' }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        kind: { type: string, enum: [individual, business] }
        display_name: { type: string }
        first_name: { type: string }
        last_name: { type: string }
        company_name: { type: string }
        primary_email: { type: string }
        primary_phone: { type: string }
        customer_code: { type: string }
        preferred_logical_guid: { type: string }
        logical_guid: { type: string }
        tags:
          type: array
          items: { type: string }
        external_refs:
          type: array
          items: { $ref: '#/components/schemas/ExternalRef' }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        notes: { type: string }
      required: [request_context, reason, source_refs]
    Customer:
      type: object
      properties:
        customer_guid: { type: string }
        status: { type: string, enum: [active, inactive, merged, doomed] }
        kind: { type: string, enum: [individual, business] }
        display_name: { type: string }
        first_name: { type: string }
        last_name: { type: string }
        company_name: { type: string }
        primary_email: { type: string }
        primary_phone: { type: string }
        customer_code: { type: string }
        preferred_logical_guid: { type: string }
        logical_guid: { type: string }
        tags:
          type: array
          items: { type: string }
        external_refs:
          type: array
          items: { $ref: '#/components/schemas/ExternalRef' }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        loyalty_tier: { type: string }
        loyalty_balance: { $ref: '#/components/schemas/LoyaltyBalance' }
        merged_to_guid: { type: string }
        merged_at: { type: string, format: date-time }
        merge_reason: { type: string }
        merged_by: { type: string }
        revision: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
    Address:
      type: object
      properties:
        line1: { type: string }
        line2: { type: string }
        city: { type: string }
        region: { type: string }
        postal_code: { type: string }
        country_code: { type: string }
    AccountTerms:
      type: object
      properties:
        terms_code: { type: string }
        net_days: { type: number }
        discount_days: { type: number }
        discount_percent: { type: number }
        due_day: { type: number }
        notes: { type: string }
    AccountDraft:
      type: object
      properties:
        request_context: { $ref: '#/components/schemas/RequestContext' }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        account_code: { type: string }
        company_name: { type: string }
        display_name: { type: string }
        tax_id: { type: string }
        tax_id_kind: { type: string }
        terms: { $ref: '#/components/schemas/AccountTerms' }
        credit_limit: { $ref: '#/components/schemas/Money' }
        credit_used: { $ref: '#/components/schemas/Money' }
        credit_hold: { type: boolean }
        sales_rep_ref: { type: string }
        billing_address: { $ref: '#/components/schemas/Address' }
        shipping_address: { $ref: '#/components/schemas/Address' }
        tags:
          type: array
          items: { type: string }
        external_refs:
          type: array
          items: { $ref: '#/components/schemas/ExternalRef' }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        notes: { type: string }
        logical_guid: { type: string }
      required: [request_context, reason, source_refs, company_name]
    Account:
      type: object
      properties:
        account_guid: { type: string }
        status: { type: string, enum: [active, inactive, suspended, doomed] }
        account_code: { type: string }
        company_name: { type: string }
        display_name: { type: string }
        tax_id: { type: string }
        tax_id_kind: { type: string }
        terms: { $ref: '#/components/schemas/AccountTerms' }
        credit_limit: { $ref: '#/components/schemas/Money' }
        credit_used: { $ref: '#/components/schemas/Money' }
        credit_available: { $ref: '#/components/schemas/Money' }
        credit_hold: { type: boolean }
        sales_rep_ref: { type: string }
        billing_address: { $ref: '#/components/schemas/Address' }
        shipping_address: { $ref: '#/components/schemas/Address' }
        tags:
          type: array
          items: { type: string }
        external_refs:
          type: array
          items: { $ref: '#/components/schemas/ExternalRef' }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        notes: { type: string }
        logical_guid: { type: string }
        revision: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
    AccountContactDraft:
      type: object
      properties:
        request_context: { $ref: '#/components/schemas/RequestContext' }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        account_guid: { type: string }
        display_name: { type: string }
        first_name: { type: string }
        last_name: { type: string }
        title: { type: string }
        email: { type: string }
        phone: { type: string }
        roles:
          type: array
          items: { type: string, enum: [buyer, approver, payer, sales_rep, viewer] }
        customer_guid: { type: string }
        tags:
          type: array
          items: { type: string }
        external_refs:
          type: array
          items: { $ref: '#/components/schemas/ExternalRef' }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [request_context, reason, source_refs, account_guid]
    AccountContact:
      type: object
      properties:
        contact_guid: { type: string }
        account_guid: { type: string }
        status: { type: string, enum: [active, inactive, suspended, doomed] }
        roles:
          type: array
          items: { type: string, enum: [buyer, approver, payer, sales_rep, viewer] }
        display_name: { type: string }
        first_name: { type: string }
        last_name: { type: string }
        title: { type: string }
        email: { type: string }
        phone: { type: string }
        customer_guid: { type: string }
        tags:
          type: array
          items: { type: string }
        external_refs:
          type: array
          items: { $ref: '#/components/schemas/ExternalRef' }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        revision: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
    CustomerCreateRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        customer: { $ref: '#/components/schemas/CustomerDraft' }
        idempotency_key: { type: string }
        cccode: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [customer, reason, source_refs]
    AccountCreateRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        account: { $ref: '#/components/schemas/AccountDraft' }
        idempotency_key: { type: string }
        cccode: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [account, reason, source_refs]
    CustomerGetRequest:
      type: object
      properties:
        customer_guid: { type: string }
        customer_code: { type: string }
        external_ref: { $ref: '#/components/schemas/ExternalRef' }
      anyOf:
        - required: [customer_guid]
        - required: [customer_code]
        - required: [external_ref]
    AccountGetRequest:
      type: object
      properties:
        account_guid: { type: string }
        account_code: { type: string }
        external_ref: { $ref: '#/components/schemas/ExternalRef' }
      anyOf:
        - required: [account_guid]
        - required: [account_code]
        - required: [external_ref]
    CustomerListRequest:
      type: object
      properties:
        status: { type: string }
        kind: { type: string }
        q: { type: string }
        email: { type: string }
        phone: { type: string }
        tag: { type: string }
        created_from: { type: string, format: date-time }
        created_to: { type: string, format: date-time }
        limit: { type: integer }
        next_token: { type: string }
    AccountListRequest:
      type: object
      properties:
        status: { type: string }
        account_code: { type: string }
        q: { type: string }
        tag: { type: string }
        credit_hold: { type: boolean }
        limit: { type: integer }
        next_token: { type: string }
    AccountStatusSetRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        account_guid: { type: string }
        status: { type: string }
        expected_revision: { type: integer }
        idempotency_key: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [account_guid, status, reason, source_refs]
    AccountUpdateRequest:
      type: object
      properties:
        account_guid: { type: string }
        expected_revision: { type: integer }
        company_name: { type: string }
        display_name: { type: string }
        tax_id: { type: string }
        tax_id_kind: { type: string }
        terms: { $ref: '#/components/schemas/AccountTerms' }
        credit_limit: { $ref: '#/components/schemas/Money' }
        credit_used: { $ref: '#/components/schemas/Money' }
        credit_hold: { type: boolean }
        sales_rep_ref: { type: string }
        billing_address: { $ref: '#/components/schemas/Address' }
        shipping_address: { $ref: '#/components/schemas/Address' }
        tags:
          type: array
          items: { type: string }
        external_refs:
          type: array
          items: { $ref: '#/components/schemas/ExternalRef' }
        notes: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [account_guid, expected_revision, reason, source_refs]
    AccountContactCreateRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        contact: { $ref: '#/components/schemas/AccountContactDraft' }
        idempotency_key: { type: string }
        cccode: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [contact, reason, source_refs]
    AccountContactGetRequest:
      type: object
      properties:
        contact_guid: { type: string }
      required: [contact_guid]
    AccountContactListRequest:
      type: object
      properties:
        account_guid: { type: string }
        status: { type: string }
        role: { type: string }
        q: { type: string }
        limit: { type: integer }
        next_token: { type: string }
    AccountContactStatusSetRequest:
      type: object
      properties:
        contact_guid: { type: string }
        status: { type: string }
        expected_revision: { type: integer }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [contact_guid, status, expected_revision, reason, source_refs]
    AccountContactUpdateRequest:
      type: object
      properties:
        contact_guid: { type: string }
        expected_revision: { type: integer }
        display_name: { type: string }
        first_name: { type: string }
        last_name: { type: string }
        title: { type: string }
        email: { type: string }
        phone: { type: string }
        roles:
          type: array
          items: { type: string, enum: [buyer, approver, payer, sales_rep, viewer] }
        customer_guid: { type: string }
        tags:
          type: array
          items: { type: string }
        external_refs:
          type: array
          items: { $ref: '#/components/schemas/ExternalRef' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [contact_guid, expected_revision, reason, source_refs]
    CustomerSearchRequest:
      type: object
      properties:
        q: { type: string }
        mode: { type: string, enum: [prefix, contains, regex], default: contains }
        status: { type: string }
        customer_code: { type: string }
        primary_email: { type: string }
        primary_phone: { type: string }
        tag: { type: string }
        limit: { type: integer }
        next_token: { type: string }
      required: [q]
    CustomerDedupeRequest:
      type: object
      properties:
        customer_guid: { type: string }
        match:
          type: object
          properties:
            email: { type: string }
            phone: { type: string }
            customer_code: { type: string }
            external_ref: { $ref: '#/components/schemas/ExternalRef' }
        limit: { type: integer }
        next_token: { type: string }
      anyOf:
        - required: [customer_guid]
        - required: [match]
    CustomerDedupeMatchField:
      type: object
      properties:
        field:
          type: string
          enum: [primary_email, primary_phone, customer_code, external_ref]
        value: { type: string }
        system: { type: string }
        external_id: { type: string }
      required: [field]
    CustomerDedupeMatch:
      type: object
      properties:
        customer: { $ref: '#/components/schemas/Customer' }
        match_fields:
          type: array
          items: { $ref: '#/components/schemas/CustomerDedupeMatchField' }
      required: [customer, match_fields]
    CustomerEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                customer: { $ref: '#/components/schemas/Customer' }
              required: [customer]
    AccountEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                account: { $ref: '#/components/schemas/Account' }
              required: [account]
    CustomerListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                customers:
                  type: array
                  items: { $ref: '#/components/schemas/Customer' }
                next_token: { type: string }
              required: [customers]
    AccountListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                accounts:
                  type: array
                  items: { $ref: '#/components/schemas/Account' }
                next_token: { type: string }
              required: [accounts]
    AccountContactEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                contact: { $ref: '#/components/schemas/AccountContact' }
              required: [contact]
    AccountContactListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                contacts:
                  type: array
                  items: { $ref: '#/components/schemas/AccountContact' }
                next_token: { type: string }
              required: [contacts]
    CustomerDedupeEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                matches:
                  type: array
                  items: { $ref: '#/components/schemas/CustomerDedupeMatch' }
                next_token: { type: string }
              required: [matches]
    CustomerConsentInput:
      type: object
      properties:
        consent_type: { type: string }
        consent_state: { type: string }
        effective_at: { type: string, format: date-time }
        expires_at: { type: string, format: date-time }
        channel_code: { type: string }
        notes: { type: string }
        expected_revision: { type: integer }
      required: [consent_type, consent_state]
    CustomerConsent:
      type: object
      properties:
        consent_type: { type: string }
        consent_state: { type: string }
        effective_at: { type: string, format: date-time }
        expires_at: { type: string, format: date-time }
        channel_code: { type: string }
        notes: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        revision: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
      required: [consent_type, consent_state]
    CustomerPreferences:
      type: object
      properties:
        preferences: { type: object, additionalProperties: true }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        revision: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
    CustomerConsentSetRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        customer_guid: { type: string }
        consents:
          type: array
          items: { $ref: '#/components/schemas/CustomerConsentInput' }
        preferences: { type: object, additionalProperties: true }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
      required: [customer_guid, reason, source_refs]
    CustomerConsentGetRequest:
      type: object
      properties:
        customer_guid: { type: string }
        limit: { type: integer }
        next_token: { type: object }
      required: [customer_guid]
    CustomerConsentEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                customer_guid: { type: string }
                consents:
                  type: array
                  items: { $ref: '#/components/schemas/CustomerConsent' }
                preferences: { $ref: '#/components/schemas/CustomerPreferences' }
                next_token: { type: object }
    CustomerMergeRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        source_customer_guid: { type: string }
        target_customer_guid: { type: string }
        expected_revision: { type: integer }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
      required: [source_customer_guid, target_customer_guid, reason, source_refs]
    CustomerMergeRecord:
      type: object
      properties:
        source_customer_guid: { type: string }
        target_customer_guid: { type: string }
        direction: { type: string, enum: [source, target] }
        counterpart_guid: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        merged_at: { type: string, format: date-time }
        merged_by: { type: string }
      required: [source_customer_guid, target_customer_guid, direction, merged_at]
    CustomerMergeListRequest:
      type: object
      properties:
        customer_guid: { type: string }
        direction: { type: string, enum: [source, target] }
        limit: { type: integer }
        next_token: { type: object }
      required: [customer_guid]
    CustomerMergeListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                customer_guid: { type: string }
                merges:
                  type: array
                  items: { $ref: '#/components/schemas/CustomerMergeRecord' }
                next_token: { type: object }
              required: [customer_guid, merges]
    CustomerFlag:
      type: object
      properties:
        flag_id: { type: string }
        flag_type: { type: string }
        status: { type: string, enum: [open, cleared] }
        severity: { type: string, enum: [low, medium, high] }
        reason_codes:
          type: array
          items: { type: string }
        notes: { type: string }
        expires_at: { type: string, format: date-time }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        revision: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
      required: [flag_id, flag_type, status, severity]
    FraudSignal:
      type: object
      properties:
        kind: { type: string }
        value: { type: string }
      required: [kind, value]
    CustomerFraudAssessment:
      type: object
      properties:
        assessment_id: { type: string }
        customer_guid: { type: string }
        action_type: { type: string }
        action_ref: { type: string }
        score: { type: number }
        risk_level: { type: string, enum: [low, medium, high, critical] }
        decision: { type: string, enum: [allow, hold] }
        decision_reasons:
          type: array
          items: { type: string }
        hold_required: { type: boolean }
        reason_codes:
          type: array
          items: { type: string }
        notes: { type: string }
        amount: { $ref: '#/components/schemas/Money' }
        signals:
          type: array
          items: { $ref: '#/components/schemas/FraudSignal' }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        occurred_at: { type: string, format: date-time }
        created_at: { type: string, format: date-time }
      required: [assessment_id, customer_guid, action_type, risk_level, decision]
    CustomerHold:
      type: object
      properties:
        hold_id: { type: string }
        customer_guid: { type: string }
        action_type: { type: string }
        action_ref: { type: string }
        assessment_id: { type: string }
        status: { type: string, enum: [pending, approved, rejected, cancelled, expired] }
        risk_level: { type: string, enum: [low, medium, high, critical] }
        score: { type: number }
        reason_codes:
          type: array
          items: { type: string }
        notes: { type: string }
        expires_at: { type: string, format: date-time }
        decision_reasons:
          type: array
          items: { type: string }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        resolution: { type: string, enum: [approved, rejected, cancelled, expired] }
        resolution_reason: { type: string }
        resolved_by: { type: string }
        resolved_at: { type: string, format: date-time }
        revision: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
      required: [hold_id, customer_guid, action_type, status]
    ExemptionCertificateScope:
      type: object
      properties:
        channel_codes:
          type: array
          items: { type: string }
        logical_guids:
          type: array
          items: { type: string }
        jurisdiction_codes:
          type: array
          items: { type: string }
    ExemptionCertificate:
      type: object
      properties:
        certificate_id: { type: string }
        certificate_code: { type: string }
        status: { type: string, enum: [active, inactive, suspended, revoked, expired] }
        status_reason: { type: string }
        customer_guid: { type: string }
        issuer: { type: string }
        issued_at: { type: string, format: date-time }
        valid_from: { type: string, format: date-time }
        valid_to: { type: string, format: date-time }
        tax_codes:
          type: array
          items: { type: string }
        jurisdiction_codes:
          type: array
          items: { type: string }
        scope: { $ref: '#/components/schemas/ExemptionCertificateScope' }
        note: { type: string }
        external_ref: { $ref: '#/components/schemas/ExternalRef' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        revision: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
      required: [certificate_id, status]
    ExemptionCertificateCreateRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        certificate:
          type: object
          properties:
            certificate_id: { type: string }
            certificate_code: { type: string }
            status: { type: string }
            customer_guid: { type: string }
            issuer: { type: string }
            issued_at: { type: string, format: date-time }
            valid_from: { type: string, format: date-time }
            valid_to: { type: string, format: date-time }
            tax_codes:
              type: array
              items: { type: string }
            jurisdiction_codes:
              type: array
              items: { type: string }
            scope: { $ref: '#/components/schemas/ExemptionCertificateScope' }
            note: { type: string }
            external_ref: { $ref: '#/components/schemas/ExternalRef' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
      required: [certificate, reason, source_refs]
    ExemptionCertificateGetRequest:
      type: object
      properties:
        certificate_id: { type: string }
      required: [certificate_id]
    ExemptionCertificateListRequest:
      type: object
      properties:
        customer_guid: { type: string }
        status: { type: string }
        limit: { type: integer }
        next_token: { type: string }
    ExemptionCertificateStatusSetRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        certificate_id: { type: string }
        status: { type: string }
        expected_revision: { type: integer }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
      required: [certificate_id, status, reason, source_refs]
    CustomerFlagSetRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        customer_guid: { type: string }
        flag:
          type: object
          properties:
            flag_id: { type: string }
            flag_type: { type: string }
            status: { type: string }
            severity: { type: string }
            reason_codes:
              type: array
              items: { type: string }
            notes: { type: string }
            expires_at: { type: string, format: date-time }
            expected_revision: { type: integer }
          required: [flag_type]
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
      required: [customer_guid, flag, reason, source_refs]
    CustomerFlagListRequest:
      type: object
      properties:
        customer_guid: { type: string }
        status: { type: string }
        flag_type: { type: string }
        limit: { type: integer }
        next_token: { type: string }
      required: [customer_guid]
    CustomerFraudAssessRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        customer_guid: { type: string }
        assessment:
          type: object
          properties:
            assessment_id: { type: string }
            action_type: { type: string }
            action_ref: { type: string }
            score: { type: number }
            risk_level: { type: string }
            decision_reasons:
              type: array
              items: { type: string }
            hold_required: { type: boolean }
            reason_codes:
              type: array
              items: { type: string }
            notes: { type: string }
            amount: { $ref: '#/components/schemas/Money' }
            signals:
              type: array
              items: { $ref: '#/components/schemas/FraudSignal' }
            policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
            occurred_at: { type: string, format: date-time }
            expires_at: { type: string, format: date-time }
          required: [action_type]
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
      required: [customer_guid, assessment, reason, source_refs]
    CustomerFraudListRequest:
      type: object
      properties:
        customer_guid: { type: string }
        action_type: { type: string }
        risk_level: { type: string }
        created_from: { type: string, format: date-time }
        created_to: { type: string, format: date-time }
        limit: { type: integer }
        next_token: { type: string }
      required: [customer_guid]
    CustomerHoldListRequest:
      type: object
      properties:
        customer_guid: { type: string }
        status: { type: string }
        action_type: { type: string }
        limit: { type: integer }
        next_token: { type: string }
      required: [customer_guid]
    CustomerHoldResolveRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        customer_guid: { type: string }
        hold_id: { type: string }
        resolution: { type: string, enum: [approved, rejected, cancelled, expired] }
        expected_revision: { type: integer }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
      required: [customer_guid, hold_id, resolution, reason, source_refs]
    CustomerFlagEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                customer_guid: { type: string }
                flag: { $ref: '#/components/schemas/CustomerFlag' }
              required: [customer_guid, flag]
    CustomerFlagListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                customer_guid: { type: string }
                flags:
                  type: array
                  items: { $ref: '#/components/schemas/CustomerFlag' }
                next_token: { type: string }
              required: [customer_guid, flags]
    CustomerFraudAssessEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                assessment: { $ref: '#/components/schemas/CustomerFraudAssessment' }
                hold: { $ref: '#/components/schemas/CustomerHold' }
              required: [assessment]
    CustomerFraudListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                customer_guid: { type: string }
                assessments:
                  type: array
                  items: { $ref: '#/components/schemas/CustomerFraudAssessment' }
                next_token: { type: string }
              required: [customer_guid, assessments]
    CustomerHoldEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                customer_guid: { type: string }
                hold: { $ref: '#/components/schemas/CustomerHold' }
              required: [customer_guid, hold]
    CustomerHoldListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                customer_guid: { type: string }
                holds:
                  type: array
                  items: { $ref: '#/components/schemas/CustomerHold' }
                next_token: { type: string }
              required: [customer_guid, holds]
    ExemptionCertificateEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                certificate: { $ref: '#/components/schemas/ExemptionCertificate' }
              required: [certificate]
    ExemptionCertificateListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                certificates:
                  type: array
                  items: { $ref: '#/components/schemas/ExemptionCertificate' }
                next_token: { type: string }
              required: [certificates]
    LoyaltyTxn:
      type: object
      properties:
        loyalty_txn_id: { type: string }
        customer_guid: { type: string }
        order_ref: { type: string }
        related_txn_id: { type: string }
        points_delta: { type: integer }
        mode: { type: string, enum: [earn, redeem, adjust, expire, reverse, restore] }
        loyalty_policy_version: { type: string }
        redeem_value: { type: number }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        occurred_at: { type: string, format: date-time }
        balance_after: { $ref: '#/components/schemas/LoyaltyBalance' }
    LoyaltyEarnRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        customer_guid: { type: string }
        order_ref: { type: string }
        logical_guid: { type: string }
        channel_code: { type: string }
        amount: { $ref: '#/components/schemas/Money' }
        tender_codes:
          type: array
          items: { type: string }
        discounted: { type: boolean }
        markdown: { type: boolean }
        vip_card_present: { type: boolean }
        location_participation: { type: boolean }
        loyalty_policy_version: { type: string }
        idempotency_key: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [customer_guid, order_ref, amount, reason, source_refs]
    LoyaltyRedeemRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        customer_guid: { type: string }
        order_ref: { type: string }
        logical_guid: { type: string }
        channel_code: { type: string }
        redeem_points: { type: integer }
        loyalty_policy_version: { type: string }
        idempotency_key: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [customer_guid, order_ref, redeem_points, reason, source_refs]
    LoyaltyAdjustRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        customer_guid: { type: string }
        points_delta: { type: integer }
        order_ref: { type: string }
        loyalty_policy_version: { type: string }
        expires_at: { type: string, format: date-time }
        idempotency_key: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [customer_guid, points_delta, reason, source_refs]
    LoyaltyReverseRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        customer_guid: { type: string }
        loyalty_txn_id: { type: string }
        order_ref: { type: string }
        loyalty_policy_version: { type: string }
        idempotency_key: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [customer_guid, reason, source_refs]
    LoyaltyRestoreRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        customer_guid: { type: string }
        loyalty_txn_id: { type: string }
        order_ref: { type: string }
        loyalty_policy_version: { type: string }
        expires_at: { type: string, format: date-time }
        idempotency_key: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [customer_guid, reason, source_refs]
    LoyaltyExpireRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        customer_guid: { type: string }
        loyalty_policy_version: { type: string }
        as_of_utc: { type: string, format: date-time }
        idempotency_key: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [customer_guid, reason, source_refs]
    LoyaltyTxnEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                transaction: { $ref: '#/components/schemas/LoyaltyTxn' }
                balance: { $ref: '#/components/schemas/LoyaltyBalance' }
              required: [transaction, balance]
    LoyaltyExpireEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                customer_guid: { type: string }
                expired_points: { type: integer }
                balance: { $ref: '#/components/schemas/LoyaltyBalance' }
                transaction: { $ref: '#/components/schemas/LoyaltyTxn' }
              required: [customer_guid, expired_points, balance]
    StoredValue:
      type: object
      properties:
        card_code: { type: string }
        status: { type: string, enum: [active, redeemed, expired, voided] }
        balance: { $ref: '#/components/schemas/Money' }
        issued_amount: { $ref: '#/components/schemas/Money' }
        issued_at: { type: string, format: date-time }
        expires_at: { type: string, format: date-time }
        customer_guid: { type: string }
        policy_versions:
          type: object
          properties:
            stored_value_policy_version: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        revision: { type: integer }
    StoredValueIssueRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        amount: { $ref: '#/components/schemas/Money' }
        customer_guid: { type: string }
        logical_guid: { type: string }
        channel_code: { type: string }
        expires_at: { type: string, format: date-time }
        external_ref: { $ref: '#/components/schemas/ExternalRef' }
        idempotency_key: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [amount, reason, source_refs]
    StoredValueRedeemRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        card_code: { type: string }
        order_ref: { type: string }
        amount: { $ref: '#/components/schemas/Money' }
        logical_guid: { type: string }
        channel_code: { type: string }
        idempotency_key: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [card_code, order_ref, amount, reason, source_refs]
    StoredValueEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                stored_value: { $ref: '#/components/schemas/StoredValue' }
              required: [stored_value]
    LoyaltyTierMultiplier:
      type: object
      properties:
        tier_code: { type: string }
        multiplier: { type: number, minimum: 0 }
      required: [tier_code, multiplier]
    LoyaltyExpiryBucket:
      type: object
      properties:
        expires_at: { type: string, format: date-time }
        points: { type: integer, minimum: 0 }
      required: [points]
    TenderEarnFactor:
      type: object
      properties:
        tender_code: { type: string }
        factor_pct: { type: number, minimum: 0, maximum: 100 }
      required: [tender_code, factor_pct]
    LoyaltyEarnPolicy:
      type: object
      properties:
        points_per_unit: { type: number, minimum: 0 }
        tier_multipliers:
          type: array
          items: { $ref: '#/components/schemas/LoyaltyTierMultiplier' }
        tender_earn_factors:
          type: array
          items: { $ref: '#/components/schemas/TenderEarnFactor' }
        earn_on_markdown: { type: boolean }
        earn_on_discount: { type: boolean }
        vip_card_required: { type: boolean }
      required: [points_per_unit]
    LoyaltyRedemptionBucket:
      type: object
      properties:
        points: { type: integer, minimum: 0 }
        value: { type: number, minimum: 0 }
      required: [points, value]
    LoyaltyRedeemPolicy:
      type: object
      properties:
        mode: { type: string, enum: [per_point, tiered] }
        points_per_unit: { type: number, minimum: 0 }
        buckets:
          type: array
          items: { $ref: '#/components/schemas/LoyaltyRedemptionBucket' }
      required: [mode]
    LoyaltyExpiryPolicy:
      type: object
      properties:
        expiry_days: { type: integer, minimum: 0 }
        rolling_expiry: { type: boolean }
    LoyaltyPolicy:
      type: object
      properties:
        policy_version: { type: string }
        effective_from: { type: string, format: date-time }
        effective_to: { type: string, format: date-time }
        earn_policy: { $ref: '#/components/schemas/LoyaltyEarnPolicy' }
        redeem_policy: { $ref: '#/components/schemas/LoyaltyRedeemPolicy' }
        expiry_policy: { $ref: '#/components/schemas/LoyaltyExpiryPolicy' }
        max_redeem_amount: { type: number, minimum: 0 }
        allow_multi_redeem_per_day: { type: boolean }
        location_participation_required: { type: boolean }
        home_store_settlement_enabled: { type: boolean }
        notes: { type: string }
      required: [policy_version, earn_policy, redeem_policy]
    LoyaltyPolicyGetRequest:
      type: object
      properties:
        as_of: { type: string, format: date-time }
        policy_version: { type: string }
        channel_code: { type: string }
        logical_guid: { type: string }
    LoyaltyPolicySetRequest:
      type: object
      properties:
        policy: { $ref: '#/components/schemas/LoyaltyPolicy' }
        expected_revision: { type: integer }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [policy, reason, source_refs]
    LoyaltyPolicyEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                policy: { $ref: '#/components/schemas/LoyaltyPolicy' }
                revision: { type: integer }
              required: [policy]
    CommentAttachment:
      type: object
      properties:
        mrs_guid: { type: string }
        caption: { type: string }
        filename: { type: string }
        content_type: { type: string }
        size_bytes: { type: integer, minimum: 0 }
      required: [mrs_guid]
    Comment:
      type: object
      properties:
        comment_id: { type: string }
        target_type: { type: string }
        target_id: { type: string }
        parent_comment_id: { type: string }
        caption: { type: string }
        body: { type: string }
        attachments:
          type: array
          items: { $ref: '#/components/schemas/CommentAttachment' }
        total_size_bytes: { type: integer }
        hashtags:
          type: array
          items: { type: string }
        mentions_users:
          type: array
          items: { type: string }
        mentions_teams:
          type: array
          items: { type: string }
        status: { type: string, enum: [current, archived, doomed] }
        current_revision: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        author_guid: { type: string }
      required: [comment_id, target_type, target_id, status, current_revision, created_at]
    CommentAddRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        target_type: { type: string }
        target_id: { type: string }
        parent_comment_id: { type: string }
        caption: { type: string }
        body: { type: string }
        attachments:
          type: array
          items: { $ref: '#/components/schemas/CommentAttachment' }
        hashtags:
          type: array
          items: { type: string }
        mentions_users:
          type: array
          items: { type: string }
        mentions_teams:
          type: array
          items: { type: string }
        idempotency_key: { type: string }
      required: [target_type, target_id]
    CommentGetRequest:
      type: object
      properties:
        comment_id: { type: string }
        target_type: { type: string }
        target_id: { type: string }
      required: [comment_id, target_type, target_id]
    CommentListRequest:
      type: object
      properties:
        target_type: { type: string }
        target_id: { type: string }
        user_guid: { type: string }
        org_wide: { type: boolean }
        status: { type: string, enum: [current, archived, doomed] }
        hashtag: { type: string }
        created_after: { type: string, format: date-time }
        created_before: { type: string, format: date-time }
        limit: { type: integer, minimum: 1, maximum: 100 }
        next_token: { type: string }
      description: Requires target_type+target_id, user_guid, or org_wide=true.
    CommentReviseRequest:
      type: object
      properties:
        comment_id: { type: string }
        target_type: { type: string }
        target_id: { type: string }
        caption: { type: string }
        body: { type: string }
        attachments:
          type: array
          items: { $ref: '#/components/schemas/CommentAttachment' }
        hashtags:
          type: array
          items: { type: string }
        mentions_users:
          type: array
          items: { type: string }
        mentions_teams:
          type: array
          items: { type: string }
        expected_revision: { type: integer }
      required: [comment_id, target_type, target_id]
    CommentStatusRequest:
      type: object
      properties:
        comment_id: { type: string }
        target_type: { type: string }
        target_id: { type: string }
        status: { type: string, enum: [current, archived, doomed] }
      required: [comment_id, target_type, target_id, status]
    CommentReportRequest:
      type: object
      properties:
        limit: { type: integer, minimum: 1, maximum: 100 }
    CommentEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                comment: { $ref: '#/components/schemas/Comment' }
              required: [comment]
    CommentListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                items:
                  type: array
                  items: { $ref: '#/components/schemas/Comment' }
                next_token: { type: string }
              required: [items]
    CommentReportEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      comment_id: { type: string }
                      target_type: { type: string }
                      target_id: { type: string }
                      total_size_bytes: { type: integer }
                      created_at: { type: string, format: date-time }
                    required: [comment_id, target_type, target_id]
              required: [items]
    InboxNotification:
      type: object
      properties:
        notification_id: { type: string }
        team_guid: { type: string }
        status: { type: string, enum: [inbox, archived] }
        state: { type: string, enum: [pending, completed, deferred] }
        priority: { type: string, enum: [low, medium, high, show_stopper] }
        act_by: { type: string, format: date-time }
        record_type: { type: string }
        record_id: { type: string }
        title: { type: string }
        body: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        created_by: { type: string }
      required: [notification_id, team_guid, status, state, priority, title]
    InboxCreateRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        team_guid: { type: string }
        record_type: { type: string }
        record_id: { type: string }
        title: { type: string }
        body: { type: string }
        priority: { type: string, enum: [low, medium, high, show_stopper] }
        act_by: { type: string, format: date-time }
        idempotency_key: { type: string }
      required: [team_guid, title]
    InboxGetRequest:
      type: object
      properties:
        notification_id: { type: string }
      required: [notification_id]
    InboxListRequest:
      type: object
      properties:
        team_guid: { type: string }
        org_wide: { type: boolean }
        status: { type: string, enum: [inbox, archived] }
        state: { type: string, enum: [pending, completed, deferred] }
        limit: { type: integer, minimum: 1, maximum: 100 }
        next_token: { type: string }
      description: Requires team_guid unless org_wide=true (owner-only).
    InboxStatusRequest:
      type: object
      properties:
        notification_id: { type: string }
        status: { type: string, enum: [inbox, archived] }
      required: [notification_id, status]
    InboxStateRequest:
      type: object
      properties:
        notification_id: { type: string }
        state: { type: string, enum: [pending, completed, deferred] }
      required: [notification_id, state]
    InboxEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                notification: { $ref: '#/components/schemas/InboxNotification' }
              required: [notification]
    InboxListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                items:
                  type: array
                  items: { $ref: '#/components/schemas/InboxNotification' }
                next_token: { type: string }
              required: [items]
    Subscription:
      type: object
      properties:
        subscription_id: { type: string }
        customer_id: { type: string }
        plan_id: { type: string }
        status: { type: string, enum: [active, paused, cancelled, expired] }
        frequency: { type: string, enum: [daily, weekly, biweekly, monthly, quarterly, annually] }
        next_billing_date: { type: string, format: date-time }
        started_at: { type: string, format: date-time }
        cycle_number: { type: integer }
        paused_at: { type: string, format: date-time }
        resumed_at: { type: string, format: date-time }
        cancelled_at: { type: string, format: date-time }
        cancellation_reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        reason: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: integer }
    SubscriptionCreateRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        subscription:
          type: object
          properties:
            request_context: { $ref: '#/components/schemas/RequestContext' }
            subscription_id: { type: string }
            customer_id: { type: string }
            plan_id: { type: string }
            frequency: { type: string, enum: [daily, weekly, biweekly, monthly, quarterly, annually] }
            next_billing_date: { type: string, format: date-time }
          required: [customer_id, plan_id, frequency]
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
      required: [subscription, reason, source_refs]
    SubscriptionGetRequest:
      type: object
      properties:
        subscription_id: { type: string }
      required: [subscription_id]
    SubscriptionListRequest:
      type: object
      properties:
        status: { type: string }
        customer_id: { type: string }
        limit: { type: integer, minimum: 1, maximum: 256, default: 8 }
        next_token: { type: string }
    SubscriptionLifecycleRequest:
      type: object
      properties:
        subscription_id: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        expected_revision: { type: integer }
        cancellation_reason: { type: string }
      required: [subscription_id, reason, source_refs]
    SubscriptionEnvelope:
      type: object
      properties:
        success: { type: boolean }
        data:
          type: object
          properties:
            subscription: { $ref: '#/components/schemas/Subscription' }
    SubscriptionListEnvelope:
      type: object
      properties:
        success: { type: boolean }
        data:
          type: object
          properties:
            subscriptions:
              type: array
              items: { $ref: '#/components/schemas/Subscription' }
            next_token: { type: string }
paths:
  /stat:
    get:
      summary: Health check
      description: |
        Health check. Tenant routes require x-orgcode; /stat health checks do not. Org-scoped reads may
        return 404 for non-associated callers (anti-enumeration). Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 5
      x-concurrency-target: 2
      x-latency-p95-ms: 500
      responses:
        '200':
          description: ok
          content:
            application/json:
              schema:
                allOf:
                  - { $ref: '#/components/schemas/Envelope' }
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          service: { type: string }
                          status: { type: string }
  /customer/create:
    post:
      summary: Create customer (draft)
      description: |
        Create customer (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. If this updates a revisioned record, expected_revision is required (428 if missing; 409
        on mismatch). Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 1000
      x-concurrency-target: 2000
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerCreateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerEnvelope' }
  /customer/get:
    post:
      summary: Get customer (draft)
      description: |
        Get customer (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Org-scoped reads may return 404 for non-associated callers (anti-enumeration). Route
        class Tier C (p95 150ms, p99 400ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 3000
      x-concurrency-target: 4000
      x-latency-p95-ms: 150
      x-latency-p99-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerEnvelope' }
  /customer/list:
    post:
      summary: List customers (draft)
      description: |
        List customers (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Paginated with limit/next_token (default 8; clamp 1–256). Route class Tier B (p95
        300ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerListEnvelope' }
  /account/create:
    post:
      summary: Create B2B account (draft)
      description: |
        Create B2B account (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. If this updates a revisioned record, expected_revision is required (428 if missing; 409
        on mismatch). Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 800
      x-concurrency-target: 1600
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AccountCreateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountEnvelope' }
  /account/get:
    post:
      summary: Get B2B account (draft)
      description: |
        Get B2B account (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Org-scoped reads may return 404 for non-associated callers (anti-enumeration). Route
        class Tier C (p95 150ms, p99 400ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 3000
      x-concurrency-target: 4000
      x-latency-p95-ms: 150
      x-latency-p99-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AccountGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountEnvelope' }
  /account/list:
    post:
      summary: List B2B accounts (draft)
      description: |
        List B2B accounts (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Paginated with limit/next_token (default 8; clamp 1–256). Route class Tier B (p95
        300ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AccountListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountListEnvelope' }
  /account/status/set:
    post:
      summary: Set B2B account status (draft)
      description: |
        Set B2B account status (draft). Auth is via headers; org identity uses x-orgcode or body placement
        as documented. If this updates a revisioned record, expected_revision is required (428 if missing;
        409 on mismatch). Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 400
      x-concurrency-target: 800
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AccountStatusSetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountEnvelope' }
  /account/update:
    post:
      summary: Update B2B account (draft)
      description: |
        Update B2B account (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. If this updates a revisioned record, expected_revision is required (428 if missing; 409
        on mismatch). Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 400
      x-concurrency-target: 800
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AccountUpdateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountEnvelope' }
  /account/credit/consume:
    post:
      summary: Atomically consume B2B account credit (M6)
      description: |
        Atomically increment credit_used on a B2B account. Uses optimistic-locking via expected_revision.
        Returns 409 conflict if revision has changed (caller should re-read and retry).
        Returns 409 credit-limit-exceeded if new credit_used would exceed credit_limit.
        Returns 409 credit-hold if account is on hold or not active.
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 400
      x-concurrency-target: 800
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [account_guid, amount, expected_revision, reason, source_refs]
              properties:
                account_guid: { type: string }
                amount: { $ref: '#/components/schemas/Money' }
                expected_revision: { type: integer }
                order_id: { type: string }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountEnvelope' }
  /account/credit/release:
    post:
      summary: Release B2B account credit (M6)
      description: |
        Decrement credit_used on a B2B account (floor at 0). Used on order cancel to return
        previously consumed credit. Does not require revision check (idempotent release).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 400
      x-concurrency-target: 800
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [account_guid, amount, reason, source_refs]
              properties:
                account_guid: { type: string }
                amount: { $ref: '#/components/schemas/Money' }
                order_id: { type: string }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountEnvelope' }
  /account/contact/create:
    post:
      summary: Create B2B account contact (draft)
      description: |
        Create B2B account contact (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 800
      x-concurrency-target: 1600
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AccountContactCreateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountContactEnvelope' }
  /account/contact/get:
    post:
      summary: Get B2B account contact (draft)
      description: |
        Get B2B account contact (draft). Auth is via headers; org identity uses x-orgcode or body placement
        as documented. Org-scoped reads may return 404 for non-associated callers (anti-enumeration). Route
        class Tier C (p95 150ms, p99 400ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 3000
      x-concurrency-target: 4000
      x-latency-p95-ms: 150
      x-latency-p99-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AccountContactGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountContactEnvelope' }
  /account/contact/list:
    post:
      summary: List B2B account contacts (draft)
      description: |
        List B2B account contacts (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Paginated with limit/next_token (default 8; clamp 1–256). Route class Tier
        B (p95 300ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AccountContactListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountContactListEnvelope' }
  /account/contact/status/set:
    post:
      summary: Set B2B account contact status (draft)
      description: |
        Set B2B account contact status (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 400
      x-concurrency-target: 800
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AccountContactStatusSetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountContactEnvelope' }
  /account/contact/update:
    post:
      summary: Update B2B account contact (draft)
      description: |
        Update B2B account contact (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 400
      x-concurrency-target: 800
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/AccountContactUpdateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/AccountContactEnvelope' }
  /customer/search:
    post:
      summary: Search customers (partial match)
      description: |
        Search customers (partial match). Auth is via headers; org identity uses x-orgcode or body placement
        as documented. Search results may be eventually consistent; use exact-match reads for immediate
        consistency. Route class Tier C (p95 250ms, p99 600ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 1000
      x-concurrency-target: 1500
      x-latency-p95-ms: 250
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerSearchRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerListEnvelope' }
  /customer/dedupe/list:
    post:
      summary: List potential customer duplicates (draft)
      description: |
        List potential customer duplicates (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Paginated with limit/next_token (default 8; clamp 1–256). Route class Tier
        C (p95 250ms, p99 600ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 1000
      x-concurrency-target: 1500
      x-latency-p95-ms: 250
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerDedupeRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerDedupeEnvelope' }
  /customer/consent/set:
    post:
      summary: Set customer consent/preferences (draft)
      description: |
        Set customer consent/preferences (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 500
      x-concurrency-target: 1000
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerConsentSetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerConsentEnvelope' }
  /customer/consent/get:
    post:
      summary: Get customer consent/preferences (draft)
      description: |
        Get customer consent/preferences (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). Route class Tier C (p95 150ms, p99 400ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 1500
      x-concurrency-target: 2500
      x-latency-p95-ms: 150
      x-latency-p99-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerConsentGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerConsentEnvelope' }
  /exemption/certificate/create:
    post:
      summary: Create exemption certificate (draft)
      description: |
        Create exemption certificate (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier C (p95 350ms, p99 800ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 200
      x-concurrency-target: 400
      x-latency-p95-ms: 350
      x-latency-p99-ms: 800
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ExemptionCertificateCreateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExemptionCertificateEnvelope' }
  /exemption/certificate/get:
    post:
      summary: Get exemption certificate (draft)
      description: |
        Get exemption certificate (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Org-scoped reads may return 404 for non-associated callers
        (anti-enumeration). Route class Tier B (p95 200ms, p99 500ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 500
      x-concurrency-target: 800
      x-latency-p95-ms: 200
      x-latency-p99-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ExemptionCertificateGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExemptionCertificateEnvelope' }
  /exemption/certificate/list:
    post:
      summary: List exemption certificates (draft)
      description: |
        List exemption certificates (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Paginated with limit/next_token (default 8; clamp 1–256). Route class Tier
        B (p95 250ms, p99 600ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 500
      x-concurrency-target: 800
      x-latency-p95-ms: 250
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ExemptionCertificateListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExemptionCertificateListEnvelope' }
  /exemption/certificate/status/set:
    post:
      summary: Set exemption certificate status (draft)
      description: |
        Set exemption certificate status (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier C (p95 350ms, p99 800ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 200
      x-concurrency-target: 400
      x-latency-p95-ms: 350
      x-latency-p99-ms: 800
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ExemptionCertificateStatusSetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExemptionCertificateEnvelope' }
  /customer/merge:
    post:
      summary: Merge customer into another customer (draft)
      description: |
        Merge customer into another customer (draft). Auth is via headers; org identity uses x-orgcode or
        body placement as documented. Route class Tier A (p95 500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerMergeRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerEnvelope' }
  /customer/merge/list:
    post:
      summary: List customer merge audit records (draft)
      description: |
        List customer merge audit records (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Paginated with limit/next_token (default 8; clamp 1–256). Route class Tier
        C (p95 250ms, p99 600ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 1000
      x-concurrency-target: 1500
      x-latency-p95-ms: 250
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerMergeListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerMergeListEnvelope' }
  /customer/flag/set:
    post:
      summary: Set customer fraud/abuse flag (draft)
      description: |
        Set customer fraud/abuse flag (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 300
      x-concurrency-target: 600
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerFlagSetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerFlagEnvelope' }
  /customer/flag/list:
    post:
      summary: List customer fraud/abuse flags (draft)
      description: |
        List customer fraud/abuse flags (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Paginated with limit/next_token (default 8; clamp 1–256). Route class Tier
        C (p95 150ms, p99 400ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 1500
      x-concurrency-target: 2500
      x-latency-p95-ms: 150
      x-latency-p99-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerFlagListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerFlagListEnvelope' }
  /customer/fraud/assess:
    post:
      summary: Assess customer fraud risk (draft)
      description: |
        Assess customer fraud risk (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Route class Tier C (p95 250ms, p99 600ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 1500
      x-concurrency-target: 2500
      x-latency-p95-ms: 250
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerFraudAssessRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerFraudAssessEnvelope' }
  /customer/fraud/list:
    post:
      summary: List customer fraud assessments (draft)
      description: |
        List customer fraud assessments (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Paginated with limit/next_token (default 8; clamp 1–256). Route class Tier
        C (p95 250ms, p99 600ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 1000
      x-concurrency-target: 1500
      x-latency-p95-ms: 250
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerFraudListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerFraudListEnvelope' }
  /customer/hold/list:
    post:
      summary: List customer holds (draft)
      description: |
        List customer holds (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Paginated with limit/next_token (default 8; clamp 1–256). Route class Tier C (p95 250ms,
        p99 600ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 1000
      x-concurrency-target: 1500
      x-latency-p95-ms: 250
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerHoldListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerHoldListEnvelope' }
  /customer/hold/resolve:
    post:
      summary: Resolve customer hold (draft)
      description: |
        Resolve customer hold (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Org-scoped reads may return 404 for non-associated callers (anti-enumeration). Route
        class Tier D (p95 350ms, p99 700ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 300
      x-concurrency-target: 600
      x-latency-p95-ms: 350
      x-latency-p99-ms: 700
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CustomerHoldResolveRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerHoldEnvelope' }
  /loyalty/earn:
    post:
      summary: Earn loyalty points (draft)
      description: |
        Earn loyalty points (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 1000
      x-concurrency-target: 2000
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/LoyaltyEarnRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/LoyaltyTxnEnvelope' }
  /loyalty/preview:
    post:
      summary: Preview loyalty earn estimate (read-only)
      description: |
        Returns estimated loyalty points for a given amount using the real org policy,
        tier multiplier, and tender factors. No transaction created, no balance mutated.
        Route class Tier C (p95 200ms, p99 400ms).
      x-status: draft
      x-route-class: Tier C
      x-qps-target: 2000
      x-concurrency-target: 4000
      x-latency-p95-ms: 200
      x-latency-p99-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [customer_guid, amount]
              properties:
                customer_guid: { type: string, format: uuid }
                amount: { oneOf: [{ type: number }, { type: object, properties: { currency: { type: string }, amount: { type: number } } }] }
                tender_codes: { type: array, items: { type: string } }
                loyalty_policy_version: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  success: { type: boolean }
                  data:
                    type: object
                    properties:
                      estimated_earn: { type: integer }
                      points_per_unit: { type: number }
                      tier_multiplier: { type: number }
                      tender_factor_pct: { type: number }
                      policy_version: { type: string }
  /loyalty/recalculate:
    post:
      summary: Recalculate loyalty balance from all transactions
      description: |
        Re-queries all loyalty transactions, rebuilds balance from scratch.
        Use to fix out-of-sync balances.
      x-status: active
      x-route-class: Tier D
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 1000
      x-latency-p99-ms: 2000
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [customer_guid]
              properties:
                customer_guid: { type: string, format: uuid }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                properties:
                  success: { type: boolean }
                  data:
                    type: object
                    properties:
                      customer_guid: { type: string }
                      old_balance: { type: object }
                      new_balance: { type: object }
                      changed: { type: boolean }
                      txn_count: { type: integer }
  /loyalty/redeem:
    post:
      summary: Redeem loyalty points (draft)
      description: |
        Redeem loyalty points (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 300
      x-concurrency-target: 400
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/LoyaltyRedeemRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/LoyaltyTxnEnvelope' }
  /loyalty/adjust:
    post:
      summary: Adjust loyalty points (draft)
      description: |
        Adjust loyalty points (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 300
      x-concurrency-target: 600
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/LoyaltyAdjustRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/LoyaltyTxnEnvelope' }
  /loyalty/reverse:
    post:
      summary: Reverse loyalty points (draft)
      description: |
        Reverse loyalty points (draft). Auth is via headers; org identity uses x-orgcode or body placement
        as documented. Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 300
      x-concurrency-target: 600
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/LoyaltyReverseRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/LoyaltyTxnEnvelope' }
  /loyalty/restore:
    post:
      summary: Restore loyalty points (draft)
      description: |
        Restore loyalty points (draft). Auth is via headers; org identity uses x-orgcode or body placement
        as documented. Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 300
      x-concurrency-target: 600
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/LoyaltyRestoreRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/LoyaltyTxnEnvelope' }
  /loyalty/expire:
    post:
      summary: Expire loyalty points as-of (draft)
      description: |
        Expire loyalty points as-of (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 300
      x-concurrency-target: 600
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/LoyaltyExpireRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/LoyaltyExpireEnvelope' }
  /loyalty/policy/get:
    post:
      summary: Get loyalty policy (draft)
      description: |
        Get loyalty policy (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Org-scoped reads may return 404 for non-associated callers (anti-enumeration). Route
        class Tier B (p95 300ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/LoyaltyPolicyGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/LoyaltyPolicyEnvelope' }
  /loyalty/policy/set:
    post:
      summary: Set loyalty policy (draft)
      description: |
        Set loyalty policy (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. If this updates a revisioned record, expected_revision is required (428 if missing; 409
        on mismatch). Route class Tier A (p95 500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/LoyaltyPolicySetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/LoyaltyPolicyEnvelope' }
  /giftcard/issue:
    post:
      summary: Issue gift card (draft)
      description: |
        Issue gift card (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. If this updates a revisioned record, expected_revision is required (428 if missing; 409
        on mismatch). Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 1000
      x-concurrency-target: 2000
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/StoredValueIssueRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/StoredValueEnvelope' }
  /giftcard/redeem:
    post:
      summary: Redeem gift card (draft)
      description: |
        Redeem gift card (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Route class Tier D (p95 300ms, p99 600ms).
      x-status: draft
      x-route-class: Tier D
      x-qps-target: 1000
      x-concurrency-target: 2000
      x-latency-p95-ms: 300
      x-latency-p99-ms: 600
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/StoredValueRedeemRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/StoredValueEnvelope' }
  /comment:
    post:
      summary: Add comment (draft)
      description: |
        Add comment (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Route class Tier A (p95 500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CommentAddRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CommentEnvelope' }
  /comment/get:
    post:
      summary: Get comment (draft)
      description: |
        Get comment (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Org-scoped reads may return 404 for non-associated callers (anti-enumeration). Route
        class Tier B (p95 300ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CommentGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CommentEnvelope' }
  /comment/list:
    post:
      summary: List comments (draft)
      description: |
        List comments (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Paginated with limit/next_token (default 8; clamp 1–256). Route class Tier B (p95
        300ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CommentListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CommentListEnvelope' }
  /comment/revise:
    post:
      summary: Revise comment (draft)
      description: |
        Revise comment (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Route class Tier A (p95 500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CommentReviseRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CommentEnvelope' }
  /comment/status:
    post:
      summary: Update comment status (draft)
      description: |
        Update comment status (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. If this updates a revisioned record, expected_revision is required (428 if missing; 409
        on mismatch). Route class Tier A (p95 500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CommentStatusRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CommentEnvelope' }
  /comment/report:
    post:
      summary: Report top-N largest comments (draft)
      description: |
        Report top-N largest comments (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Route class Tier A (p95 500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/CommentReportRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CommentReportEnvelope' }
  /inbox/create:
    post:
      summary: Create inbox notification (draft)
      description: |
        Create inbox notification (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. If this updates a revisioned record, expected_revision is required (428 if
        missing; 409 on mismatch). Route class Tier A (p95 500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/InboxCreateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/InboxEnvelope' }
  /inbox/get:
    post:
      summary: Get inbox notification (draft)
      description: |
        Get inbox notification (draft). Auth is via headers; org identity uses x-orgcode or body placement
        as documented. Org-scoped reads may return 404 for non-associated callers (anti-enumeration). Route
        class Tier B (p95 300ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/InboxGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/InboxEnvelope' }
  /inbox/list:
    post:
      summary: List inbox notifications (draft)
      description: |
        List inbox notifications (draft). Auth is via headers; org identity uses x-orgcode or body placement
        as documented. Paginated with limit/next_token (default 8; clamp 1–256). Route class Tier B (p95
        300ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/InboxListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/InboxListEnvelope' }
  /inbox/status:
    post:
      summary: Update inbox status (draft)
      description: |
        Update inbox status (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. If this updates a revisioned record, expected_revision is required (428 if missing; 409
        on mismatch). Route class Tier A (p95 500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/InboxStatusRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/InboxEnvelope' }
  /inbox/state:
    post:
      summary: Update inbox state (draft)
      description: |
        Update inbox state (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Route class Tier A (p95 500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/InboxStateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/InboxEnvelope' }
  /subscription/create:
    post:
      operationId: subscriptionCreate
      summary: Create a customer subscription
      description: |
        Create a new subscription for a customer tied to a subscription plan.
        Route class Tier A (p95 500ms).
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SubscriptionCreateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SubscriptionEnvelope' }
  /subscription/get:
    post:
      operationId: subscriptionGet
      summary: Get a subscription by ID
      x-route-class: Tier A
      x-qps-target: 200
      x-concurrency-target: 200
      x-latency-p95-ms: 200
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SubscriptionGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SubscriptionEnvelope' }
  /subscription/list:
    post:
      operationId: subscriptionList
      summary: List subscriptions with optional status/customer filter
      x-route-class: Tier A
      x-qps-target: 200
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SubscriptionListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SubscriptionListEnvelope' }
  /subscription/pause:
    post:
      operationId: subscriptionPause
      summary: Pause an active subscription
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SubscriptionLifecycleRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SubscriptionEnvelope' }
  /subscription/resume:
    post:
      operationId: subscriptionResume
      summary: Resume a paused subscription
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SubscriptionLifecycleRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SubscriptionEnvelope' }
  /subscription/cancel:
    post:
      operationId: subscriptionCancel
      summary: Cancel an active or paused subscription
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' }, { $ref: '#/components/parameters/LogicalHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/SubscriptionLifecycleRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SubscriptionEnvelope' }
  /warranty/register:
    post:
      operationId: warrantyRegister
      summary: Register a warranty linking serial to customer and terms
      description: |
        Create a warranty registration with idempotency. Resolves G51 (warranty registration entity).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 200
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [warranty, reason, source_refs]
              properties:
                warranty:
                  $ref: '#/components/schemas/WarrantyRegistrationDraft'
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
                idempotency_key: { type: string }
              x-idempotency-scope: WARRANTY_REGISTER
              x-idempotency-retention-hours: 24
              x-idempotency-replay: true
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/WarrantyEnvelope' }
  /warranty/get:
    post:
      operationId: warrantyGet
      summary: Get warranty by warranty_id or serial_number
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 500
      x-concurrency-target: 1000
      x-latency-p95-ms: 100
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                warranty_id: { type: string }
                serial_number: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/WarrantyEnvelope' }
  /warranty/list:
    post:
      operationId: warrantyList
      summary: List warranties by status, customer_id, or serial_number (paginated)
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 300
      x-concurrency-target: 500
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                status: { type: string, enum: [active, expired, voided, doomed] }
                customer_id: { type: string }
                serial_number: { type: string }
                limit: { type: integer }
                next_token: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/WarrantyListEnvelope' }
  /warranty/status/set:
    post:
      operationId: warrantyStatusSet
      summary: Transition warranty status (active → expired/voided/doomed)
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [warranty_id, status, reason, source_refs]
              properties:
                warranty_id: { type: string }
                status: { type: string, enum: [active, expired, voided, doomed] }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
                expected_revision: { type: integer }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/WarrantyEnvelope' }
  /warranty/update:
    post:
      operationId: warrantyUpdate
      summary: Update warranty terms, expiry, or customer with expected_revision
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [warranty_id, reason, source_refs, expected_revision]
              properties:
                warranty_id: { type: string }
                warranty_start: { type: string }
                warranty_expiry: { type: string }
                plan_code: { type: string }
                customer_id: { type: string }
                terms: { $ref: '#/components/schemas/WarrantyTerms' }
                purchase_date: { type: string }
                purchase_order_id: { type: string }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
                expected_revision: { type: integer }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/WarrantyEnvelope' }
  /customer/delete:
    post:
      operationId: customerDelete
      summary: Delete all customer data (CCPA right-to-delete)
      description: |
        Permanently deletes a customer and all customer-adjacent DDB records (consent, fraud,
        holds, flags, merge audit, loyalty txns, subscriptions, warranties, exemption certs)
        plus lookup indexes (email, phone, code, external refs, status). Also removes the
        customer from the search index. Emits customer-deleted event. Resolves G55.
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 10
      x-concurrency-target: 50
      x-latency-p95-ms: 2000
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [customer_guid, reason, source_refs]
              properties:
                customer_guid: { type: string }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                allOf:
                  - { $ref: '#/components/schemas/Envelope' }
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          customer_guid: { type: string }
                          items_deleted: { type: integer }
  /customer/anonymize:
    post:
      operationId: customerAnonymize
      summary: Anonymize customer PII (CCPA right-to-forget with analytics preservation)
      description: |
        Replaces PII fields with redacted tokens, removes email/phone lookup indexes,
        transitions status to anonymized, removes from search. Customer-adjacent data
        (loyalty, fraud, consent, etc.) is preserved for analytics. Resolves G56.
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 10
      x-concurrency-target: 50
      x-latency-p95-ms: 1000
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [customer_guid, reason, source_refs]
              properties:
                customer_guid: { type: string }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/CustomerEnvelope' }
  /retention/policy/set:
    post:
      operationId: retentionPolicySet
      summary: Set data retention policy for the org
      description: |
        Configures per-org data retention rules (customer retention days, loyalty txn
        retention days, etc.). Uses current+versioned dual-record pattern with
        expected_revision guard. Resolves G57.
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 5
      x-concurrency-target: 20
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [policy, reason, source_refs]
              properties:
                policy:
                  type: object
                  required: [policy_version]
                  properties:
                    policy_version: { type: string }
                    customer_retention_days: { type: integer, nullable: true }
                    loyalty_txn_retention_days: { type: integer, nullable: true }
                    fraud_assessment_retention_days: { type: integer, nullable: true }
                    consent_retention_days: { type: integer, nullable: true }
                    auto_anonymize: { type: boolean }
                    effective_from: { type: string, format: date-time }
                    effective_to: { type: string, format: date-time }
                expected_revision: { type: integer }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                allOf:
                  - { $ref: '#/components/schemas/Envelope' }
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          policy: { type: object }
                          revision: { type: integer }
  /retention/policy/get:
    post:
      operationId: retentionPolicyGet
      summary: Get current or versioned data retention policy
      description: |
        Retrieves the current retention policy, a specific version, or the effective
        policy as-of a given date.
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 200
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                policy_version: { type: string }
                as_of: { type: string, format: date-time }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                allOf:
                  - { $ref: '#/components/schemas/Envelope' }
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          policy: { type: object }
                          revision: { type: integer }
