type: object
description: |
    Customer face-scan submission — the first step in the fabricator pipeline.
    Mirrors `FabricatorSchemas.ScanRequest`. Created when a Big Order needs custom
    cushions; the customer uploads scan data via the iOS app, the preprocessor
    measures IPD + pupil locations, then the request transitions to
    `ReadyForFabricator` and `Job`s are spawned from it.
required: [id, ownerBigscreenAccountId, bigOrderId, scanRequestState]
properties:
    id: { type: string }
    createdAt: { type: string, format: date-time }
    ownerBigscreenAccountId: { type: string, description: Customer account that owns the scan. }
    creatorBigscreenAccountId: { type: string, description: Account that created the request. }
    bigOrderId: { type: string, description: Originating Big Order. }
    topologyPatientId:
        type: string
        description: Patient id forwarded to the Topology service for prescription alignment.
    topologyAuthToken:
        type: string
        description: Auth token used to fetch Topology data for this patient.
    name:
        type: string
        description: Operator-supplied label.
    scanRequestState:
        type: string
        description: |
            State-machine position. Values in `FabricatorSchemas.ScanRequestState`
            (`Idle`, `AwaitingCustomer`, `AwaitingPreprocessor`, `ReadyForFabricator`,
            `PreprocessorFailed`, `Cancelled`, etc.). Immutable except via `applyAction`.
    history:
        type: array
        items: { type: object, additionalProperties: true }
    scanSnapshot:
        type: object
        additionalProperties: true
        description: Snapshot of the most recent uploaded scan.
    shopifyIpd:
        type: integer
        description: IPD as specified by the customer on Shopify (-1 if unset).
    preprocessorIpd:
        type: integer
        description: IPD measured by the preprocessor (-1 if not yet run).
    preprocessorLeftPupil:
        type: array
        items: { type: number }
        description: Left pupil pixel coordinates from the preprocessor.
    preprocessorRightPupil:
        type: array
        items: { type: number }
    preprocessorResult:
        type: string
        description: "`FabricatorSchemas.PreprocessorResult` — outcome of the most recent preprocessor run."
    ipd:
        type: integer
        description: Final IPD value (-1 if not determined).
    jobIds:
        type: array
        items: { type: string }
        description: Jobs spawned from this scan (loose linkage — jobs can outlive the request).
    version:
        type: string
        example: V2
    scanRequestType:
        type: string
        description: |
            `FabricatorSchemas.ScanRequestType` — `Default` for full scan flows,
            `IpdOnly` when the request is just for an IPD update without a new
            cushion job.
example:
    id: "scan_01HXJ58DQX5N9P2VRC8B3MZ7Y4"
    createdAt: "2026-04-08T18:05:42.000Z"
    ownerBigscreenAccountId: "acct_01HXJ4Q12345"
    creatorBigscreenAccountId: "acct_01HXJ4Q12345"
    bigOrderId: "01HXJ4S3M0Q3TRBQ3JV9P5W2VC"
    name: "First scan"
    scanRequestState: "ReadyForFabricator"
    shopifyIpd: 63
    preprocessorIpd: 62
    preprocessorLeftPupil: [302.4, 478.1]
    preprocessorRightPupil: [482.7, 478.0]
    preprocessorResult: "Success"
    ipd: 62
    jobIds: ["job_01HXY8ZW7Q9V0K3M5RPQ4ABCDE"]
    version: "V2"
    scanRequestType: "Default"
    history: []
