openapi: 3.1.0
info:
  title: Accounting API
  version: 0.1.0-draft
  description: |
    Accounting / ERP Readiness.

    Contract notes:
    - API Gateway base path: `/accounting`
    - Org-gated: supply `x-orgcode`.
    - 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.
    - Exposes exportable financial event views for downstream systems.
servers:
  - url: https://api.g3nretailstack.com/accounting
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 }
  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: [accounting] }
        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 }
        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 }
        storage_policy_version: { type: string }
      additionalProperties: true
    Money:
      type: object
      properties:
        currency: { type: string }
        amount: { type: number }
      required: [currency, amount]
    TaxComponent:
      type: object
      properties:
        tax_code: { type: string }
        jurisdiction_code: { type: string }
        rate: { type: number }
        taxable_base: { $ref: '#/components/schemas/Money' }
        tax_basis: { type: string, enum: [included, added] }
        holiday_applied: { type: boolean }
        exemption_applied: { type: boolean }
        exemption_reason: { type: string }
        amount: { $ref: '#/components/schemas/Money' }
    AccountingEvent:
      type: object
      properties:
        event_id: { type: string }
        event_type: { type: string }
        orgcode: { type: string }
        logical_guid: { type: string }
        channel_code: { type: string }
        cccode: { type: string }
        amount: { $ref: '#/components/schemas/Money' }
        tax_amount: { $ref: '#/components/schemas/Money' }
        tax_policy_version: { type: string }
        tax_basis: { type: string, enum: [included, added] }
        tax_liability_trigger: { type: string, enum: [order, invoice, shipment] }
        tax_jurisdiction_code: { type: string }
        tax_holiday_applied: { type: boolean }
        tax_override_applied: { type: boolean }
        tax_components:
          type: array
          items: { $ref: '#/components/schemas/TaxComponent' }
        occurred_at: { type: string, format: date-time }
        request_context: { $ref: '#/components/schemas/RequestContext' }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [event_id, event_type, orgcode, occurred_at, request_context, reason, source_refs]
    EventRecordRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        event_id: { type: string }
        event_type: { type: string }
        occurred_at: { type: string, format: date-time }
        logical_guid: { type: string }
        channel_code: { type: string }
        cccode: { type: string }
        amount: { $ref: '#/components/schemas/Money' }
        tax_amount: { $ref: '#/components/schemas/Money' }
        tax_policy_version: { type: string }
        tax_basis: { type: string, enum: [included, added] }
        tax_liability_trigger: { type: string, enum: [order, invoice, shipment] }
        tax_jurisdiction_code: { type: string }
        tax_holiday_applied: { type: boolean }
        tax_override_applied: { type: boolean }
        tax_components:
          type: array
          items: { $ref: '#/components/schemas/TaxComponent' }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
        request_context: { $ref: '#/components/schemas/RequestContext' }
      required: [event_type, occurred_at, request_context, reason, source_refs]
    EventGetRequest:
      type: object
      properties:
        event_id: { type: string }
      required: [event_id]
    EventListRequest:
      type: object
      properties:
        event_types:
          type: array
          items: { type: string }
        logical_guid: { type: string }
        channel_code: { type: string }
        cccode: { type: string }
        from_utc: { type: string, format: date-time }
        to_utc: { type: string, format: date-time }
        limit: { type: integer }
        next_token: { type: string }
    LineageListRequest:
      type: object
      properties:
        source_ref: { $ref: '#/components/schemas/SourceRef' }
        limit: { type: integer }
        next_token: { type: string }
      required: [source_ref]
    ReconcileReportRequest:
      type: object
      properties:
        from_utc: { type: string, format: date-time }
        to_utc: { type: string, format: date-time }
        event_types:
          type: array
          items: { type: string }
        limit: { type: integer }
        next_token: { type: string }
      required: [from_utc, to_utc]
    EventListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                events:
                  type: array
                  items: { $ref: '#/components/schemas/AccountingEvent' }
                next_token: { type: string }
              required: [events]
    EventEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                event: { $ref: '#/components/schemas/AccountingEvent' }
              required: [event]
    LineageListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                lineage:
                  type: array
                  items:
                    type: object
                    properties:
                      event_id: { type: string }
                      event_type: { type: string }
                      occurred_at: { type: string, format: date-time }
                      logical_guid: { type: string }
                      channel_code: { type: string }
                      cccode: { type: string }
                      source_ref: { $ref: '#/components/schemas/SourceRef' }
                      reason: { type: string }
                next_token: { type: string }
              required: [lineage]
    ReconcileReportEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                report:
                  type: object
                  properties:
                    from_utc: { type: string, format: date-time }
                    to_utc: { type: string, format: date-time }
                    event_count: { type: integer }
                    by_type:
                      type: object
                      additionalProperties: { type: integer }
                    amount_totals:
                      type: object
                      additionalProperties: { type: number }
                    tax_totals:
                      type: object
                      additionalProperties: { type: number }
                    partial: { type: boolean }
                next_token: { type: string }
              required: [report]
    StorageUsageWindow:
      type: object
      properties:
        from_utc: { type: string, format: date-time }
        to_utc: { type: string, format: date-time }
      required: [from_utc, to_utc]
    StorageUsageInput:
      type: object
      properties:
        usage_id: { type: string }
        resource_type: { type: string, enum: [s3, dynamodb] }
        resource_ref: { type: string }
        service: { type: string }
        bytes: { type: number }
        item_count: { type: integer }
        object_count: { type: integer }
        window: { $ref: '#/components/schemas/StorageUsageWindow' }
        measured_at: { type: string, format: date-time }
        logical_guid: { type: string }
        channel_code: { type: string }
        cccode: { type: string }
      required: [resource_type, resource_ref, service, bytes]
    StorageUsageRecord:
      type: object
      properties:
        usage_id: { type: string }
        resource_type: { type: string, enum: [s3, dynamodb] }
        resource_ref: { type: string }
        service: { type: string }
        bytes: { type: number }
        item_count: { type: integer }
        object_count: { type: integer }
        window: { $ref: '#/components/schemas/StorageUsageWindow' }
        measured_at: { type: string, format: date-time }
        logical_guid: { type: string }
        channel_code: { type: string }
        cccode: { type: string }
        request_context: { $ref: '#/components/schemas/RequestContext' }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
    StorageUsageRecordRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        usage: { $ref: '#/components/schemas/StorageUsageInput' }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
        request_context: { $ref: '#/components/schemas/RequestContext' }
      required: [usage, request_context, reason, source_refs]
    StorageUsageGetRequest:
      type: object
      properties:
        usage_id: { type: string }
      required: [usage_id]
    StorageUsageListRequest:
      type: object
      properties:
        resource_type: { type: string, enum: [s3, dynamodb] }
        service: { type: string }
        cccode: { type: string }
        logical_guid: { type: string }
        channel_code: { type: string }
        from_utc: { type: string, format: date-time }
        to_utc: { type: string, format: date-time }
        limit: { type: integer }
        next_token: { type: string }
    StorageUsageCursor:
      type: object
      properties:
        source_index: { type: integer }
        dt_index: { type: integer }
        org_prefix_token: { type: string }
        pending_prefixes:
          type: array
          items: { type: string }
        current_prefix: { type: string }
        continuation_token: { type: string }
        partial_bytes: { type: number }
        partial_objects: { type: integer }
        partial_record_by_cccode:
          type: object
          additionalProperties:
            type: object
            properties:
              bytes: { type: number }
              items: { type: integer }
    StorageUsageReconcileRequest:
      type: object
      properties:
        from_utc: { type: string, format: date-time }
        to_utc: { type: string, format: date-time }
        limit: { type: integer }
        dry_run: { type: boolean }
        cursor: { $ref: '#/components/schemas/StorageUsageCursor' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        request_context: { $ref: '#/components/schemas/RequestContext' }
      required: [from_utc, to_utc]
    StorageUsageEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                usage: { $ref: '#/components/schemas/StorageUsageRecord' }
              required: [usage]
    StorageUsageListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                usages:
                  type: array
                  items: { $ref: '#/components/schemas/StorageUsageRecord' }
                next_token: { type: string }
              required: [usages]
    StorageUsageReconcileEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                reconcile:
                  type: object
                  properties:
                    orgcode: { type: string }
                    window: { $ref: '#/components/schemas/StorageUsageWindow' }
                    scanned_prefixes: { type: integer }
                    processed_prefixes: { type: integer }
                    usage_records: { type: integer }
                    object_bytes: { type: number }
                    object_count: { type: integer }
                    record_bytes: { type: number }
                    record_items: { type: integer }
                    errors: { type: integer }
                    partial: { type: boolean }
                next_cursor: { $ref: '#/components/schemas/StorageUsageCursor' }
              required: [reconcile]
    UsageTotals:
      type: object
      properties:
        records: { type: integer }
        api_calls: { type: integer }
        deliveries: { type: integer }
        bandwidth_in_bytes: { type: number }
        bandwidth_out_bytes: { type: number }
        errors: { type: integer }
      required: [records, api_calls, deliveries, bandwidth_in_bytes, bandwidth_out_bytes, errors]
    UsageAggregate:
      type: object
      properties:
        totals: { $ref: '#/components/schemas/UsageTotals' }
        surfaces:
          type: object
          additionalProperties: { $ref: '#/components/schemas/UsageTotals' }
      required: [totals]
    UsageRollupRecord:
      type: object
      properties:
        rollup_id: { type: string }
        dt: { type: string, format: date }
        service: { type: string }
        scope: { type: string }
        cccode: { type: string }
        window:
          type: object
          properties:
            from_utc: { type: string, format: date-time }
            to_utc: { type: string, format: date-time }
          required: [from_utc, to_utc]
        usage: { $ref: '#/components/schemas/UsageAggregate' }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        source_stats:
          type: object
          properties:
            objects: { type: integer }
            bytes: { type: integer }
            records: { type: integer }
        run_id: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: integer }
    UsageRollupGetRequest:
      type: object
      properties:
        dt: { type: string, format: date }
        service: { type: string }
        cccode: { type: string }
      required: [dt, service]
    UsageRollupListRequest:
      type: object
      properties:
        from_dt: { type: string, format: date }
        to_dt: { type: string, format: date }
        service: { type: string }
        cccode: { type: string }
        limit: { type: integer }
        next_token: { type: object }
    UsageRollupEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                rollup: { $ref: '#/components/schemas/UsageRollupRecord' }
    UsageRollupListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                rollups:
                  type: array
                  items: { $ref: '#/components/schemas/UsageRollupRecord' }
                next_token: { type: object }
    TaxFilters:
      type: object
      properties:
        jurisdiction_codes:
          type: array
          items: { type: string }
        tax_policy_versions:
          type: array
          items: { type: string }
        tax_basis: { type: string, enum: [included, added] }
        tax_liability_trigger: { type: string, enum: [order, invoice, shipment] }
        require_tax_amount: { type: boolean }
    ExportBatch:
      type: object
      properties:
        batch_id: { type: string }
        export_id: { type: string }
        schedule_id: { type: string }
        batch_kind: { type: string, enum: [initial, repair] }
        repair_of_batch_id: { type: string }
        status: { type: string }
        format: { type: string }
        export_kind: { type: string, enum: [financial_events, tax_audit] }
        tax_filters: { $ref: '#/components/schemas/TaxFilters' }
        from_utc: { type: string, format: date-time }
        to_utc: { type: string, format: date-time }
        event_types:
          type: array
          items: { type: string }
        destination_ref: { type: string }
        policy_versions:
          type: object
          properties:
            export_policy_version: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        evidence:
          type: object
          properties:
            manifest_ref: { type: string }
            file_refs:
              type: array
              items: { type: string }
            checksum_sha256: { type: string }
            record_count: { type: integer }
            file_count: { type: integer }
            notes: { type: string }
        file_count: { type: integer }
        revision: { type: integer }
        created_at: { type: string, format: date-time }
        completed_at: { type: string, format: date-time }
        sent_at: { type: string, format: date-time }
        failed_at: { type: string, format: date-time }
    ExportScheduleCadence:
      type: object
      properties:
        type: { type: string, enum: [interval, cron] }
        interval_minutes: { type: integer }
        cron: { type: string }
        timezone: { type: string }
      required: [type, timezone]
    ExportScheduleWindow:
      type: object
      properties:
        from_offset_minutes: { type: integer }
        to_offset_minutes: { type: integer }
      required: [from_offset_minutes, to_offset_minutes]
    ExportSchedule:
      type: object
      properties:
        schedule_id: { type: string }
        status: { type: string, enum: [active, suspended] }
        cadence: { $ref: '#/components/schemas/ExportScheduleCadence' }
        window: { $ref: '#/components/schemas/ExportScheduleWindow' }
        format: { type: string }
        event_types:
          type: array
          items: { type: string }
        destination_ref: { type: string }
        policy_versions:
          type: object
          properties:
            export_policy_version: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        next_run_at: { type: string, format: date-time }
        last_run_at: { type: string, format: date-time }
        revision: { type: integer }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
    ExportBatchCreateRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        batch_id: { type: string }
        export_id: { type: string }
        schedule_id: { type: string }
        batch_kind: { type: string, enum: [initial, repair] }
        repair_of_batch_id: { type: string }
        evidence:
          type: object
          properties:
            manifest_ref: { type: string }
            file_refs:
              type: array
              items: { type: string }
            checksum_sha256: { type: string }
            record_count: { type: integer }
            file_count: { type: integer }
            notes: { type: string }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
        request_context: { $ref: '#/components/schemas/RequestContext' }
      required: [export_id, request_context, reason, source_refs]
    ExportBatchRepairRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        export_id: { type: string }
        schedule_id: { type: string }
        repair_of_batch_id: { type: string }
        evidence:
          type: object
          properties:
            manifest_ref: { type: string }
            file_refs:
              type: array
              items: { type: string }
            checksum_sha256: { type: string }
            record_count: { type: integer }
            file_count: { type: integer }
            notes: { type: string }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        idempotency_key: { type: string }
        request_context: { $ref: '#/components/schemas/RequestContext' }
      required: [export_id, repair_of_batch_id, request_context, reason, source_refs]
    ExportBatchGetRequest:
      type: object
      properties:
        batch_id: { type: string }
      required: [batch_id]
    ExportBatchListRequest:
      type: object
      properties:
        export_id: { type: string }
        schedule_id: { type: string }
        limit: { type: integer }
        next_token: { type: string }
    ExportBatchStatusSetRequest:
      type: object
      properties:
        batch_id: { type: string }
        status: { type: string, enum: [ready, sent, failed] }
        expected_revision: { type: integer }
        evidence:
          type: object
          properties:
            manifest_ref: { type: string }
            file_refs:
              type: array
              items: { type: string }
            checksum_sha256: { type: string }
            record_count: { type: integer }
            file_count: { type: integer }
            notes: { type: string }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        request_context: { $ref: '#/components/schemas/RequestContext' }
      required: [batch_id, status, expected_revision, request_context, reason, source_refs]
    ExportCreateRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        from_utc: { type: string, format: date-time }
        to_utc: { type: string, format: date-time }
        event_types:
          type: array
          items: { type: string }
        format: { type: string }
        export_kind: { type: string, enum: [financial_events, tax_audit] }
        tax_filters: { $ref: '#/components/schemas/TaxFilters' }
        idempotency_key: { type: string }
        request_context: { $ref: '#/components/schemas/RequestContext' }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [from_utc, to_utc, request_context, reason, source_refs]
    ExportScheduleCreateRequest:
      type: object
      x-idempotency-scope: orgcode+route+idempotency_key
      x-idempotency-retention-hours: 24
      x-idempotency-replay: return_original_response
      properties:
        schedule_id: { type: string }
        status: { type: string, enum: [active, suspended] }
        cadence: { $ref: '#/components/schemas/ExportScheduleCadence' }
        window: { $ref: '#/components/schemas/ExportScheduleWindow' }
        format: { type: string }
        event_types:
          type: array
          items: { type: string }
        destination_ref: { type: string }
        policy_refs: { $ref: '#/components/schemas/PolicyRefs' }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        next_run_at: { type: string, format: date-time }
        idempotency_key: { type: string }
        reason: { type: string }
        request_context: { $ref: '#/components/schemas/RequestContext' }
      required: [cadence, request_context, reason, source_refs]
    ExportGetRequest:
      type: object
      properties:
        export_id: { type: string }
      required: [export_id]
    ExportScheduleGetRequest:
      type: object
      properties:
        schedule_id: { type: string }
      required: [schedule_id]
    ExportListRequest:
      type: object
      properties:
        status: { type: string }
        from_utc: { type: string, format: date-time }
        to_utc: { type: string, format: date-time }
        limit: { type: integer }
        next_token: { type: string }
    ExportScheduleListRequest:
      type: object
      properties:
        status: { type: string, enum: [active, suspended] }
        limit: { type: integer }
        next_token: { type: string }
    ExportScheduleStatusSetRequest:
      type: object
      properties:
        schedule_id: { type: string }
        status: { type: string, enum: [active, suspended] }
        expected_revision: { type: integer }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        request_context: { $ref: '#/components/schemas/RequestContext' }
      required: [schedule_id, status, expected_revision, request_context, reason, source_refs]
    ExportEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                export: { $ref: '#/components/schemas/ExportBatch' }
              required: [export]
    ExportListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                exports:
                  type: array
                  items: { $ref: '#/components/schemas/ExportBatch' }
                next_token: { type: string }
              required: [exports]
    ExportBatchEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                batch: { $ref: '#/components/schemas/ExportBatch' }
              required: [batch]
    ExportBatchListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                batches:
                  type: array
                  items: { $ref: '#/components/schemas/ExportBatch' }
                next_token: { type: string }
              required: [batches]
    ExportScheduleEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                schedule: { $ref: '#/components/schemas/ExportSchedule' }
              required: [schedule]
    ExportScheduleListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                schedules:
                  type: array
                  items: { $ref: '#/components/schemas/ExportSchedule' }
                next_token: { type: string }
              required: [schedules]
    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]
    PaymentTerms:
      type: object
      properties:
        net_days: { type: integer }
        discount_days: { type: integer }
        discount_percent: { type: number }
        due_day: { type: integer }
    Invoice:
      type: object
      properties:
        invoice_id: { type: string }
        orgcode: { type: string }
        customer_ref: { type: string }
        account_guid: { type: string }
        account_code: { type: string }
        order_guid: { type: string }
        currency: { type: string }
        amount_minor: { type: integer }
        tax_amount_minor: { type: integer }
        paid_amount_minor: { type: integer }
        outstanding_minor: { type: integer }
        payment_terms: { $ref: '#/components/schemas/PaymentTerms' }
        due_date: { type: string, format: date }
        discount_due_date: { type: string, format: date }
        issued_at: { type: string, format: date-time }
        status:
          type: string
          enum: [open, partial, paid, overdue, written_off, cancelled]
        credit_snapshot: { type: object }
        notes: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        request_context: { $ref: '#/components/schemas/RequestContext' }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: integer }
      required: [invoice_id, orgcode, customer_ref, currency, amount_minor, due_date, status]
    ArPayment:
      type: object
      properties:
        payment_id: { type: string }
        orgcode: { type: string }
        invoice_id: { type: string }
        amount_minor: { type: integer }
        currency: { type: string }
        tender_code: { type: string }
        tender_ref: { type: string }
        processor_transaction_id: { type: string }
        applied_at: { type: string, format: date-time }
        notes: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
        request_context: { $ref: '#/components/schemas/RequestContext' }
        created_at: { type: string, format: date-time }
        revision: { type: integer }
      required: [payment_id, orgcode, invoice_id, amount_minor, currency]
    FinancialRollupRecord:
      type: object
      properties:
        rollup_id: { type: string }
        orgcode: { type: string }
        dt: { type: string, format: date }
        dimension: { type: string }
        dimension_value: { type: string }
        metrics: { type: object }
        window:
          type: object
          properties:
            from_utc: { type: string, format: date-time }
            to_utc: { type: string, format: date-time }
          required: [from_utc, to_utc]
        source_stats: { type: object }
        run_id: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: integer }
    InvoiceSetRequest:
      type: object
      properties:
        invoice:
          type: object
          properties:
            invoice_id: { type: string }
            customer_ref: { type: string }
            account_guid: { type: string }
            account_code: { type: string }
            order_guid: { type: string }
            currency: { type: string }
            amount_minor: { type: integer }
            tax_amount_minor: { type: integer }
            paid_amount_minor: { type: integer }
            payment_terms: { $ref: '#/components/schemas/PaymentTerms' }
            due_date: { type: string, format: date }
            discount_due_date: { type: string, format: date }
            issued_at: { type: string, format: date-time }
            status:
              type: string
              enum: [open, partial, paid, overdue, written_off, cancelled]
            credit_snapshot: { type: object }
            notes: { type: string }
          required: [customer_ref, currency, amount_minor, due_date]
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [invoice, reason, source_refs]
    InvoiceGetRequest:
      type: object
      properties:
        invoice_id: { type: string }
      required: [invoice_id]
    InvoiceListRequest:
      type: object
      properties:
        customer_ref: { type: string }
        status: { type: string, enum: [open, partial, paid, overdue, written_off, cancelled] }
        from_due_date: { type: string, format: date }
        to_due_date: { type: string, format: date }
        limit: { type: integer }
        next_token: { type: string }
    InvoiceStatusSetRequest:
      type: object
      properties:
        invoice_id: { type: string }
        status: { type: string, enum: [open, partial, paid, overdue, written_off, cancelled] }
        expected_revision: { type: integer }
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [invoice_id, status, reason, source_refs]
    InvoicePaymentApplyRequest:
      type: object
      properties:
        payment:
          type: object
          properties:
            invoice_id: { type: string }
            amount_minor: { type: integer }
            currency: { type: string }
            tender_code: { type: string }
            tender_ref: { type: string }
            processor_transaction_id: { type: string }
            applied_at: { type: string, format: date-time }
            notes: { type: string }
          required: [invoice_id, amount_minor, currency]
        reason: { type: string }
        source_refs: { $ref: '#/components/schemas/SourceRefs' }
      required: [payment, reason, source_refs]
    InvoicePaymentListRequest:
      type: object
      properties:
        invoice_id: { type: string }
        limit: { type: integer }
        next_token: { type: string }
      required: [invoice_id]
    ArAgingReportRequest:
      type: object
      properties:
        customer_ref: { type: string }
        as_of: { type: string, format: date }
        limit: { type: integer }
        next_token: { type: string }
    ArBalanceRequest:
      type: object
      properties:
        customer_ref: { type: string }
      required: [customer_ref]
    ArStatementRequest:
      type: object
      properties:
        customer_ref: { type: string }
        from_utc: { type: string, format: date-time }
        to_utc: { type: string, format: date-time }
        limit: { type: integer }
        next_token: { type: string }
      required: [customer_ref, from_utc, to_utc]
    FinancialRollupGetRequest:
      type: object
      properties:
        dt: { type: string, format: date }
        dimension: { type: string }
        dimension_value: { type: string }
      required: [dt, dimension]
    FinancialRollupListRequest:
      type: object
      properties:
        from_dt: { type: string, format: date }
        to_dt: { type: string, format: date }
        dimension: { type: string }
        limit: { type: integer }
        next_token: { type: object }
    InvoiceEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                invoice: { $ref: '#/components/schemas/Invoice' }
              required: [invoice]
    InvoiceListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                invoices:
                  type: array
                  items: { $ref: '#/components/schemas/Invoice' }
                next_token: { type: string }
              required: [invoices]
    ArPaymentEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                payment: { $ref: '#/components/schemas/ArPayment' }
                invoice_status: { type: string }
                invoice_outstanding_minor: { type: integer }
              required: [payment]
    ArPaymentListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                payments:
                  type: array
                  items: { $ref: '#/components/schemas/ArPayment' }
                next_token: { type: string }
              required: [payments]
    ArAgingReportEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                report:
                  type: object
                  properties:
                    as_of: { type: string, format: date }
                    customer_ref: { type: string }
                    buckets:
                      type: object
                      additionalProperties:
                        type: object
                        additionalProperties:
                          type: object
                          properties:
                            invoice_count: { type: integer }
                            outstanding_minor: { type: integer }
                    partial: { type: boolean }
                next_token: { type: string }
              required: [report]
    ArBalanceEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                customer_ref: { type: string }
                balances:
                  type: object
                  additionalProperties: { type: integer }
                invoice_count: { type: integer }
              required: [customer_ref, balances, invoice_count]
    ArStatementEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                statement:
                  type: object
                  properties:
                    customer_ref: { type: string }
                    from_utc: { type: string, format: date-time }
                    to_utc: { type: string, format: date-time }
                    entries:
                      type: array
                      items: { type: object }
                    running_balance:
                      type: object
                      additionalProperties: { type: integer }
                    partial: { type: boolean }
                next_token: { type: string }
              required: [statement]
    FinancialRollupEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                rollup: { $ref: '#/components/schemas/FinancialRollupRecord' }
    FinancialRollupListEnvelope:
      allOf:
        - { $ref: '#/components/schemas/Envelope' }
        - type: object
          properties:
            data:
              type: object
              properties:
                rollups:
                  type: array
                  items: { $ref: '#/components/schemas/FinancialRollupRecord' }
                next_token: { type: object }
    DunningPolicyInput:
      type: object
      required: [levels]
      properties:
        levels:
          type: array
          items:
            type: object
            required: [level, days_past_due, action_type, description]
            properties:
              level: { type: integer, minimum: 1 }
              days_past_due: { type: integer, minimum: 0 }
              action_type: { type: string, enum: [reminder, notice, demand, collection, write_off] }
              description: { type: string }
        auto_escalate: { type: boolean, default: false }
        grace_period_days: { type: integer, default: 0 }
        currency: { type: string }
    DunningPolicy:
      type: object
      properties:
        orgcode: { type: string }
        levels:
          type: array
          items:
            type: object
            properties:
              level: { type: integer }
              days_past_due: { type: integer }
              action_type: { type: string }
              description: { type: string }
        auto_escalate: { type: boolean }
        grace_period_days: { type: integer }
        currency: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: integer }
    DunningActionInput:
      type: object
      required: [invoice_id, level, action_type]
      properties:
        invoice_id: { type: string }
        level: { type: integer, minimum: 1 }
        action_type: { type: string, enum: [reminder, notice, demand, collection, write_off] }
        customer_ref: { type: string }
        assigned_to: { type: string }
        notes: { type: string }
        status: { type: string, enum: [pending, sent, acknowledged, escalated, resolved], default: pending }
    DunningAction:
      type: object
      properties:
        action_id: { type: string }
        invoice_id: { type: string }
        customer_ref: { type: string }
        level: { type: integer }
        action_type: { type: string }
        assigned_to: { type: string }
        notes: { type: string }
        status: { type: string }
        orgcode: { type: string }
        created_at: { type: string, format: date-time }
        updated_at: { type: string, format: date-time }
        revision: { type: integer }
    CreditHoldCheckResponse:
      type: object
      properties:
        customer_ref: { type: string }
        holds:
          type: array
          items:
            type: object
            properties:
              hold_id: { type: string }
              customer_ref: { type: string }
              customer_guid: { type: string }
              action_type: { type: string }
              status: { type: string }
              risk_level: { type: string }
              expires_at: { type: string, format: date-time }
              created_at: { type: string, format: date-time }
              updated_at: { type: string, format: date-time }
        blocked: { type: boolean }
    FinancialRollupExportResponse:
      type: object
      properties:
        s3_key: { type: string, nullable: true }
        record_count: { type: integer }
        orgcodes:
          type: array
          items: { type: string }
        message: { 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 }
  /event/list:
    post:
      summary: List financial events (draft)
      description: |
        List financial events (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/EventListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/EventListEnvelope' }
  /event/record:
    post:
      summary: Record financial event (draft)
      description: |
        Record financial event (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: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/EventRecordRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/EventEnvelope' }
  /event/get:
    post:
      summary: Get financial event (draft)
      description: |
        Get financial event (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/EventGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/EventEnvelope' }
  /lineage/list:
    post:
      summary: List lineage by source reference (draft)
      description: |
        List lineage by source reference (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/LineageListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/LineageListEnvelope' }
  /reconcile/report:
    post:
      summary: Reconciliation report (draft)
      description: |
        Reconciliation report (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Route class Tier B (p95 400ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 200
      x-concurrency-target: 300
      x-latency-p95-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ReconcileReportRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ReconcileReportEnvelope' }
  /storage/usage/record:
    post:
      summary: Record storage usage (draft)
      description: |
        Record storage usage (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 B (p95 400ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/StorageUsageRecordRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/StorageUsageEnvelope' }
  /storage/usage/get:
    post:
      summary: Get storage usage record (draft)
      description: |
        Get storage usage record (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: 200
      x-concurrency-target: 400
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/StorageUsageGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/StorageUsageEnvelope' }
  /storage/usage/list:
    post:
      summary: List storage usage records (draft)
      description: |
        List storage usage 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
        B (p95 300ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 200
      x-concurrency-target: 400
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/StorageUsageListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/StorageUsageListEnvelope' }
  /storage/usage/reconcile:
    post:
      summary: Reconcile storage usage window (draft)
      description: |
        Reconcile storage usage window (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Route class Tier B (p95 900ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 50
      x-concurrency-target: 200
      x-latency-p95-ms: 900
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/StorageUsageReconcileRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/StorageUsageReconcileEnvelope' }
  /usage/rollup/get:
    post:
      summary: Get daily usage rollup (draft)
      description: |
        Get daily usage rollup (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: 200
      x-concurrency-target: 400
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsageRollupGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsageRollupEnvelope' }
  /usage/rollup/list:
    post:
      summary: List daily usage rollups (draft)
      description: |
        List daily usage rollups (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: 200
      x-concurrency-target: 400
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/UsageRollupListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/UsageRollupListEnvelope' }
  /export/create:
    post:
      summary: Create export batch (draft)
      description: |
        Create export batch (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/ExportCreateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportEnvelope' }
  /export/get:
    post:
      summary: Get export batch (draft)
      description: |
        Get export batch (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/ExportGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportEnvelope' }
  /export/list:
    post:
      summary: List export batches (draft)
      description: |
        List export batches (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/ExportListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportListEnvelope' }
  /export/batch/create:
    post:
      summary: Create export batch (draft)
      description: |
        Create export batch (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 B (p95 400ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ExportBatchCreateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportBatchEnvelope' }
  /export/batch/repair:
    post:
      summary: Create export repair batch (draft)
      description: |
        Create export repair batch (draft). Auth is via headers; org identity uses x-orgcode or body
        placement as documented. Route class Tier B (p95 400ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 50
      x-concurrency-target: 100
      x-latency-p95-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ExportBatchRepairRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportBatchEnvelope' }
  /export/batch/get:
    post:
      summary: Get export batch (draft)
      description: |
        Get export batch (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/ExportBatchGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportBatchEnvelope' }
  /export/batch/list:
    post:
      summary: List export batches (draft)
      description: |
        List export batches (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/ExportBatchListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportBatchListEnvelope' }
  /export/batch/status/set:
    post:
      summary: Set export batch status (draft)
      description: |
        Set export batch 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 B (p95 400ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ExportBatchStatusSetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportBatchEnvelope' }
  /export/schedule/create:
    post:
      summary: Create export schedule (draft)
      description: |
        Create export schedule (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 B (p95 400ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ExportScheduleCreateRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportScheduleEnvelope' }
  /export/schedule/get:
    post:
      summary: Get export schedule (draft)
      description: |
        Get export schedule (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/ExportScheduleGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportScheduleEnvelope' }
  /export/schedule/list:
    post:
      summary: List export schedules (draft)
      description: |
        List export schedules (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/ExportScheduleListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportScheduleListEnvelope' }
  /export/schedule/status/set:
    post:
      summary: Set export schedule status (draft)
      description: |
        Set export schedule 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 B (p95 400ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ExportScheduleStatusSetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ExportScheduleEnvelope' }
  /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' }
  /invoice/set:
    post:
      summary: Create or update invoice (draft)
      description: |
        Create or update invoice (draft). Auth is via headers; org identity uses x-orgcode or body placement
        as documented. Supports AR tracking for ERP readiness. Route class Tier A (p95 500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/InvoiceSetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/InvoiceEnvelope' }
  /invoice/get:
    post:
      summary: Get invoice by ID (draft)
      description: |
        Get invoice by ID (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/InvoiceGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/InvoiceEnvelope' }
  /invoice/list:
    post:
      summary: List invoices (draft)
      description: |
        List invoices (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Supports filtering by customer_ref, status, and due date range. 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/InvoiceListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/InvoiceListEnvelope' }
  /invoice/status/set:
    post:
      summary: Set invoice status (draft)
      description: |
        Set invoice status (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Status lifecycle: open → partial → paid | overdue | written_off | cancelled. Route
        class Tier A (p95 500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/InvoiceStatusSetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/InvoiceEnvelope' }
  /invoice/payment/apply:
    post:
      summary: Apply payment to invoice (draft)
      description: |
        Apply payment to invoice (draft). Auth is via headers; org identity uses x-orgcode or body placement
        as documented. Atomically creates payment record and updates invoice balance. Route class Tier A (p95
        500ms).
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/InvoicePaymentApplyRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ArPaymentEnvelope' }
  /invoice/payment/list:
    post:
      summary: List payments for invoice (draft)
      description: |
        List payments for invoice (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/InvoicePaymentListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ArPaymentListEnvelope' }
  /ar/aging/report:
    post:
      summary: AR aging report (draft)
      description: |
        AR aging report (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Buckets: current, 1-30, 31-60, 61-90, 91-120, 120+ days past due. Supports optional
        customer_ref filter. Route class Tier B (p95 400ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 200
      x-concurrency-target: 300
      x-latency-p95-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ArAgingReportRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ArAgingReportEnvelope' }
  /ar/balance:
    post:
      summary: Per-customer AR balance (draft)
      description: |
        Per-customer AR balance (draft). Auth is via headers; org identity uses x-orgcode or body placement
        as documented. Returns outstanding balance by currency for a customer. 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/ArBalanceRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ArBalanceEnvelope' }
  /ar/statement:
    post:
      summary: Customer AR statement (draft)
      description: |
        Customer AR statement (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Returns invoices and running balance for a customer within a date range. Paginated with
        limit/next_token. Route class Tier B (p95 400ms).
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 200
      x-concurrency-target: 300
      x-latency-p95-ms: 400
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/ArStatementRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/ArStatementEnvelope' }
  /rollup/financial/get:
    post:
      summary: Get financial rollup (draft)
      description: |
        Get financial rollup (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Returns a single daily aggregated financial summary by dimension. 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: 200
      x-concurrency-target: 400
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/FinancialRollupGetRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/FinancialRollupEnvelope' }
  /rollup/financial/list:
    post:
      summary: List financial rollups (draft)
      description: |
        List financial rollups (draft). Auth is via headers; org identity uses x-orgcode or body placement as
        documented. Supports date range and dimension filtering. 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: 200
      x-concurrency-target: 400
      x-latency-p95-ms: 300
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/FinancialRollupListRequest' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/FinancialRollupListEnvelope' }
  /commission/get:
    post:
      operationId: commissionGet
      summary: Get commission record by commission_id
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 500
      x-concurrency-target: 400
      x-latency-p95-ms: 200
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [commission_id]
              properties:
                commission_id: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /commission/list:
    post:
      operationId: commissionList
      summary: List commissions by org, associate, or order
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 500
      x-concurrency-target: 400
      x-latency-p95-ms: 200
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                associate_ref: { type: string }
                order_guid: { type: string }
                period: { type: string, description: 'YYYY-MM format' }
                limit: { type: integer, minimum: 1, maximum: 256, default: 8 }
                next_token: { type: object }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /commission/adjust:
    post:
      operationId: commissionAdjust
      summary: Record a manual commission adjustment (bonus, chargeback, correction)
      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: [commission_id, adjustment_type, amount_minor, reason, source_refs]
              properties:
                commission_id: { type: string }
                adjustment_type: { type: string, description: 'e.g. bonus, chargeback, correction' }
                amount_minor: { type: integer, description: 'Signed integer (positive = bonus, negative = chargeback)' }
                notes: { type: string }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /commission/split/set:
    post:
      operationId: commissionSplitSet
      summary: Set multi-associate commission splits (must sum to 10000 bps)
      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: [commission_id, splits, reason, source_refs]
              properties:
                commission_id: { type: string }
                splits:
                  type: array
                  items:
                    type: object
                    required: [associate_ref, split_pct_bps]
                    properties:
                      associate_ref: { type: string }
                      split_pct_bps: { type: integer, minimum: 0, maximum: 10000 }
                expected_revision: { type: integer }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /commission/statement:
    post:
      operationId: commissionStatement
      summary: Get commission statement for an associate in a given period
      x-status: draft
      x-route-class: Tier B
      x-qps-target: 200
      x-concurrency-target: 400
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [associate_ref, period]
              properties:
                associate_ref: { type: string }
                period: { type: string, description: 'YYYY-MM format' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /commission/payout/create:
    post:
      operationId: commissionPayoutCreate
      summary: Create a commission payout for an associate and period
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [associate_ref, period, currency, reason, source_refs]
              properties:
                associate_ref: { type: string }
                period: { type: string, description: 'YYYY-MM format' }
                currency: { type: string }
                notes: { type: string }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  # --- Dunning (G80) ---
  /dunning/policy/set:
    post:
      operationId: dunningPolicySet
      summary: Set dunning escalation policy for org
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 300
      x-idempotency: deterministic — expected_revision guard
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [policy]
              properties:
                policy:
                  $ref: '#/components/schemas/DunningPolicyInput'
                expected_revision: { type: integer }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /dunning/policy/get:
    post:
      operationId: dunningPolicyGet
      summary: Get dunning escalation policy for org
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 500
      x-concurrency-target: 400
      x-latency-p95-ms: 200
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /dunning/action/create:
    post:
      operationId: dunningActionCreate
      summary: Record a dunning action on an overdue invoice
      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: [action]
              properties:
                action:
                  $ref: '#/components/schemas/DunningActionInput'
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /dunning/action/list:
    post:
      operationId: dunningActionList
      summary: List dunning actions for an invoice or customer
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 500
      x-concurrency-target: 400
      x-latency-p95-ms: 200
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                invoice_id: { type: string }
                customer_ref: { type: string }
                limit: { type: integer }
                next_token: { type: object }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /dunning/evaluate:
    post:
      operationId: dunningEvaluate
      summary: Evaluate overdue invoices against dunning policy (read-only)
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 100
      x-concurrency-target: 200
      x-latency-p95-ms: 500
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                limit: { type: integer }
                next_token: { type: object }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  # --- Credit Hold Check (G81) ---
  /ar/credit-hold/check:
    post:
      operationId: arCreditHoldCheck
      summary: Check active credit/payment holds for a customer
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 500
      x-concurrency-target: 400
      x-latency-p95-ms: 200
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [customer_ref]
              properties:
                customer_ref: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  # --- Financial Rollup Export (G82) ---
  /rollup/financial/export:
    post:
      operationId: financialRollupExport
      summary: Export financial rollups to S3 for date range
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 50
      x-concurrency-target: 100
      x-latency-p95-ms: 1000
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [from_dt, to_dt]
              properties:
                from_dt: { type: string, format: date, description: 'YYYY-MM-DD' }
                to_dt: { type: string, format: date, description: 'YYYY-MM-DD' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /commission/payout/get:
    post:
      operationId: commissionPayoutGet
      summary: Get commission payout by payout_id
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 500
      x-concurrency-target: 400
      x-latency-p95-ms: 200
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [payout_id]
              properties:
                payout_id: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /commission/payout/list:
    post:
      operationId: commissionPayoutList
      summary: List commission payouts by org or associate
      x-status: draft
      x-route-class: Tier A
      x-qps-target: 500
      x-concurrency-target: 400
      x-latency-p95-ms: 200
      parameters: [ { $ref: '#/components/parameters/OrgHeader' } ]
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                associate_ref: { type: string }
                limit: { type: integer, minimum: 1, maximum: 256, default: 8 }
                next_token: { type: object }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /commission/payout/status/set:
    post:
      operationId: commissionPayoutStatusSet
      summary: Advance commission payout lifecycle (pending → approved → paid)
      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: [payout_id, status, reason, source_refs]
              properties:
                payout_id: { type: string }
                status: { type: string, enum: [pending, approved, paid, cancelled] }
                expected_revision: { type: integer }
                payment_ref: { type: string, description: 'Required when status=paid' }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  # --- Consignment Settlement (G98) ---
  /consignment/settlement/create:
    post:
      summary: Create a consignment settlement
      tags: [ConsignmentSettlement]
      x-status: draft
      x-route-class: write
      x-qps-target: 10
      x-concurrency-target: 5
      x-latency-p95-ms: 400
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [vendor_ref, period_start, period_end, lines, currency]
              properties:
                vendor_ref: { type: string }
                logical_guid: { type: string }
                period_start: { type: string, format: date-time }
                period_end: { type: string, format: date-time }
                lines: { type: array, items: { type: object, properties: { variant_id: { type: string }, qty_sold: { type: integer }, unit_cost_minor: { type: integer } } } }
                currency: { type: string, default: USD }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /consignment/settlement/get:
    post:
      summary: Get a consignment settlement by ID
      tags: [ConsignmentSettlement]
      x-status: draft
      x-route-class: read
      x-qps-target: 50
      x-concurrency-target: 10
      x-latency-p95-ms: 200
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [settlement_id]
              properties:
                settlement_id: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /consignment/settlement/list:
    post:
      summary: List consignment settlements
      tags: [ConsignmentSettlement]
      x-status: draft
      x-route-class: read
      x-qps-target: 50
      x-concurrency-target: 10
      x-latency-p95-ms: 200
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                vendor_ref: { type: string }
                limit: { type: integer }
                next_token: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /consignment/settlement/approve:
    post:
      summary: Approve a consignment settlement
      tags: [ConsignmentSettlement]
      x-status: draft
      x-route-class: write
      x-qps-target: 10
      x-concurrency-target: 5
      x-latency-p95-ms: 300
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [settlement_id]
              properties:
                settlement_id: { type: string }
                expected_revision: { type: integer }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /consignment/settlement/status/set:
    post:
      summary: Set consignment settlement status
      tags: [ConsignmentSettlement]
      x-status: draft
      x-route-class: write
      x-qps-target: 10
      x-concurrency-target: 5
      x-latency-p95-ms: 300
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [settlement_id, status, reason, source_refs]
              properties:
                settlement_id: { type: string }
                status: { type: string, enum: [draft, approved, paid] }
                expected_revision: { type: integer }
                invoice_id: { type: string, description: 'Required when status=paid' }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  # --- Franchise Royalty (G99) ---
  /franchise/royalty/rule/set:
    post:
      summary: Set franchise royalty rule (dual-record)
      tags: [FranchiseRoyalty]
      x-status: draft
      x-route-class: write
      x-qps-target: 5
      x-concurrency-target: 2
      x-latency-p95-ms: 400
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [rule_type, currency, calculation_basis]
              properties:
                rule_type: { type: string, enum: [percentage, flat, tiered] }
                rate_bps: { type: integer, description: 'For percentage type' }
                flat_amount_minor: { type: integer, description: 'For flat type' }
                tiers: { type: array, items: { type: object } }
                currency: { type: string }
                calculation_basis: { type: string, enum: [gross_sales, net_sales] }
                franchise_scope: { description: '"all" or object with facility_guids' }
                effective_from: { type: string, format: date-time }
                effective_to: { type: string, format: date-time }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /franchise/royalty/rule/get:
    post:
      summary: Get current franchise royalty rule
      tags: [FranchiseRoyalty]
      x-status: draft
      x-route-class: read
      x-qps-target: 50
      x-concurrency-target: 10
      x-latency-p95-ms: 200
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties: {}
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /franchise/royalty/calculate:
    post:
      summary: Calculate franchise royalty for facility and period
      tags: [FranchiseRoyalty]
      x-status: draft
      x-route-class: write
      x-qps-target: 10
      x-concurrency-target: 5
      x-latency-p95-ms: 500
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [facility_guid, period]
              properties:
                facility_guid: { type: string }
                period: { type: string, description: 'e.g. 2026-01' }
                calculation_basis: { type: string, description: 'Override rule default' }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /franchise/royalty/get:
    post:
      summary: Get a franchise royalty record
      tags: [FranchiseRoyalty]
      x-status: draft
      x-route-class: read
      x-qps-target: 50
      x-concurrency-target: 10
      x-latency-p95-ms: 200
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [record_id]
              properties:
                record_id: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /franchise/royalty/list:
    post:
      summary: List franchise royalty records
      tags: [FranchiseRoyalty]
      x-status: draft
      x-route-class: read
      x-qps-target: 50
      x-concurrency-target: 10
      x-latency-p95-ms: 200
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                facility_guid: { type: string }
                period: { type: string }
                limit: { type: integer }
                next_token: { type: string }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
  /franchise/royalty/status/set:
    post:
      summary: Set franchise royalty record status
      tags: [FranchiseRoyalty]
      x-status: draft
      x-route-class: write
      x-qps-target: 10
      x-concurrency-target: 5
      x-latency-p95-ms: 300
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required: [record_id, status, reason, source_refs]
              properties:
                record_id: { type: string }
                status: { type: string, enum: [calculated, approved, invoiced, paid] }
                expected_revision: { type: integer }
                reason: { type: string }
                source_refs: { type: array, items: { type: object } }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }

  /inference/config/set:
    post:
      summary: Set LLM inference configuration
      operationId: accounting_inference_config_set
      tags: [Inference]
      x-status: draft
      x-route-class: write
      x-qps-target: 5
      x-concurrency-target: 3
      x-latency-p95-ms: 300
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                enabled_surfaces: { type: array, items: { type: string } }
                export_format: { type: string, enum: [ndjson, jsonl] }
                refresh_interval_hours: { type: number }
                s3_prefix: { type: string }
                status: { type: string, enum: [active, inactive] }
                expected_revision: { type: integer }
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }

  /inference/config/get:
    post:
      summary: Get LLM inference configuration
      operationId: accounting_inference_config_get
      tags: [Inference]
      x-status: draft
      x-route-class: read
      x-qps-target: 20
      x-concurrency-target: 5
      x-latency-p95-ms: 200
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }

  /inference/snapshot/create:
    post:
      summary: Create LLM inference snapshot (export to S3)
      operationId: accounting_inference_snapshot_create
      tags: [Inference]
      x-status: draft
      x-route-class: write
      x-qps-target: 5
      x-concurrency-target: 3
      x-latency-p95-ms: 2000
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Envelope' }
