{
  "openapi": "3.1.0",
  "info": {
    "title": "MovingManifest REST API",
    "version": "1.0.0",
    "description": "Agent-friendly REST API for move setup, inventory, spaces, photos, sale prep, planning context, and exports."
  },
  "servers": [
    {
      "url": "https://movingmanifest.com/api/v1"
    }
  ],
  "security": [
    {
      "bearerApiKey": []
    }
  ],
  "paths": {
    "/me": {
      "get": {
        "summary": "Inspect API key context",
        "operationId": "getApiContext",
        "responses": {
          "200": {
            "description": "API key, household, scopes, and move restriction."
          }
        }
      }
    },
    "/households/{householdId}/members": {
      "get": {
        "summary": "List household members",
        "operationId": "listHouseholdMembers",
        "parameters": [
          {
            "$ref": "#/components/parameters/householdId"
          }
        ],
        "responses": {
          "200": {
            "description": "Real household login access records. Requires members/manage."
          }
        }
      },
      "post": {
        "summary": "Add or invite a household member by email",
        "operationId": "addHouseholdMember",
        "parameters": [
          {
            "$ref": "#/components/parameters/householdId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HouseholdMemberAdd"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Existing member access or pending invitation updated."
          },
          "201": {
            "description": "Household member access created."
          },
          "202": {
            "description": "Pending household invitation created for an email that has not signed in yet."
          }
        }
      }
    },
    "/moves": {
      "get": {
        "summary": "List moves",
        "operationId": "listMoves",
        "responses": {
          "200": {
            "description": "Accessible moves."
          }
        }
      },
      "post": {
        "summary": "Create a move",
        "operationId": "createMove",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MoveCreate"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Move created."
          }
        }
      }
    },
    "/moves/setup": {
      "post": {
        "summary": "Create or update a move with spaces, transport, zones, and starter items",
        "operationId": "setupMove",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "move": {
                    "$ref": "#/components/schemas/MoveCreate"
                  },
                  "spaces": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/MoveSpace"
                    }
                  },
                  "transportResources": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "items": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/ItemInput"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Move setup result."
          },
          "201": {
            "description": "Move created and setup applied."
          }
        }
      }
    },
    "/moves/{moveId}/agent-context": {
      "get": {
        "summary": "Fetch compact move context for AI agents",
        "operationId": "getAgentContext",
        "parameters": [
          {
            "$ref": "#/components/parameters/moveId"
          }
        ],
        "responses": {
          "200": {
            "description": "Move, spaces, transport, items, photos, sale pipeline, layout plans, and AI contract."
          }
        }
      }
    },
    "/moves/{moveId}/items": {
      "get": {
        "summary": "List move items",
        "operationId": "listItems",
        "parameters": [
          {
            "$ref": "#/components/parameters/moveId"
          }
        ],
        "responses": {
          "200": {
            "description": "Inventory items."
          }
        }
      },
      "post": {
        "summary": "Create an item",
        "operationId": "createItem",
        "parameters": [
          {
            "$ref": "#/components/parameters/moveId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ItemInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Item created."
          }
        }
      }
    },
    "/moves/{moveId}/items/batch-upsert": {
      "post": {
        "summary": "Create or update up to 100 items",
        "operationId": "batchUpsertItems",
        "parameters": [
          {
            "$ref": "#/components/parameters/moveId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["items"],
                "properties": {
                  "dryRun": {
                    "type": "boolean"
                  },
                  "items": {
                    "type": "array",
                    "maxItems": 100,
                    "items": {
                      "$ref": "#/components/schemas/ItemInput"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Per-row create/update result."
          }
        }
      }
    },
    "/moves/{moveId}/spaces": {
      "get": {
        "summary": "List spaces",
        "operationId": "listMoveSpaces",
        "parameters": [
          {
            "$ref": "#/components/parameters/moveId"
          }
        ],
        "responses": {
          "200": {
            "description": "Origin, destination, transport, and custom spaces."
          }
        }
      },
      "post": {
        "summary": "Create a space",
        "operationId": "createMoveSpace",
        "parameters": [
          {
            "$ref": "#/components/parameters/moveId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MoveSpace"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Space created."
          }
        }
      }
    },
    "/moves/{moveId}/sale-listings": {
      "post": {
        "summary": "Create or update sale listing for an item",
        "operationId": "upsertSaleListing",
        "parameters": [
          {
            "$ref": "#/components/parameters/moveId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SaleListingInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sale listing updated."
          },
          "201": {
            "description": "Sale listing created."
          }
        }
      }
    },
    "/images/upload": {
      "post": {
        "summary": "Upload image evidence in one call",
        "operationId": "uploadImageEvidenceImage",
        "description": "Plain REST alias for /photos/upload using image terminology. Send raw JPEG/PNG/WebP bytes with metadata query params, multipart form data with a file field, or JSON with exactly one public sourceUrl, dataUrl, or fileBase64 image. MovingManifest stores the original, reads dimensions, finalizes the evidence record, creates web-ready derivatives server-side, can optionally queue AI photo-review suggestions, and returns agentReview so assistants can summarize assumptions without asking for every field.",
        "parameters": [
          {
            "name": "moveId",
            "in": "query",
            "description": "Required when uploading raw image bytes.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "room",
            "in": "query",
            "description": "Readable room label for raw image byte uploads.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "caption",
            "in": "query",
            "description": "Caption for raw image byte uploads.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "photoType",
            "in": "query",
            "description": "Photo type for raw image byte uploads.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "generateAiSuggestions",
            "in": "query",
            "description": "Set true for raw image byte uploads when the photo should also enter AI photo review. Requires inventory/write for queueing; upload can still succeed if review queueing fails.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PhotoDirectUpload"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PhotoMultipartUpload"
              }
            },
            "image/jpeg": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "image/png": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "image/webp": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Photo record created and derivative processing attempted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhotoDirectUploadResponse"
                }
              }
            }
          }
        }
      }
    },
    "/photos/upload": {
      "post": {
        "summary": "Upload image evidence in one call",
        "operationId": "uploadPhotoEvidenceImage",
        "description": "Default REST image upload path for agents. /images/upload is an equivalent alias when image terminology is clearer. Send raw JPEG/PNG/WebP bytes with metadata query params, multipart form data with a file field, or JSON with exactly one public sourceUrl, dataUrl, or fileBase64 image. MovingManifest stores the original, reads dimensions, finalizes the evidence record, creates web-ready derivatives server-side, can optionally queue AI photo-review suggestions, and returns agentReview so assistants can summarize assumptions without asking for every field.",
        "parameters": [
          {
            "name": "moveId",
            "in": "query",
            "description": "Required when uploading raw image bytes.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "room",
            "in": "query",
            "description": "Readable room label for raw image byte uploads.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "caption",
            "in": "query",
            "description": "Caption for raw image byte uploads.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "photoType",
            "in": "query",
            "description": "Photo type for raw image byte uploads.",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "generateAiSuggestions",
            "in": "query",
            "description": "Set true for raw image byte uploads when the photo should also enter AI photo review. Requires inventory/write for queueing; upload can still succeed if review queueing fails.",
            "schema": {
              "type": "boolean"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PhotoDirectUpload"
              }
            },
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/PhotoMultipartUpload"
              }
            },
            "image/jpeg": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "image/png": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "image/webp": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Photo record created and derivative processing attempted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PhotoDirectUploadResponse"
                }
              }
            }
          }
        }
      }
    },
    "/uploads/init": {
      "post": {
        "summary": "Start photo upload",
        "operationId": "startPhotoUpload",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UploadInit"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Presigned upload session."
          }
        }
      }
    },
    "/photos/finalize": {
      "post": {
        "summary": "Finalize photo upload",
        "operationId": "finalizePhotoUpload",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PhotoFinalize"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Photo record created."
          }
        }
      }
    },
    "/moves/{moveId}/capacity-report": {
      "get": {
        "summary": "Get capacity report",
        "operationId": "getCapacityReport",
        "parameters": [
          {
            "$ref": "#/components/parameters/moveId"
          }
        ],
        "responses": {
          "200": {
            "description": "Capacity estimates and warnings."
          }
        }
      }
    },
    "/moves/{moveId}/move-day": {
      "get": {
        "summary": "Get move-day checklist",
        "operationId": "getMoveDayChecklist",
        "parameters": [
          {
            "$ref": "#/components/parameters/moveId"
          }
        ],
        "responses": {
          "200": {
            "description": "Move-day checklist."
          }
        }
      }
    },
    "/moves/{moveId}/exports": {
      "post": {
        "summary": "Create export",
        "operationId": "createExport",
        "parameters": [
          {
            "$ref": "#/components/parameters/moveId"
          }
        ],
        "responses": {
          "201": {
            "description": "Export job created."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "MovingManifest API key beginning with mmk_."
      }
    },
    "parameters": {
      "householdId": {
        "name": "householdId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      },
      "moveId": {
        "name": "moveId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    },
    "schemas": {
      "HouseholdMemberAdd": {
        "type": "object",
        "required": ["email", "role"],
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "role": {
            "type": "string",
            "enum": ["admin", "editor", "packer", "viewer", "guest"],
            "description": "Owner access cannot be granted through the API."
          }
        }
      },
      "MoveCreate": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "originLabel": {
            "type": "string"
          },
          "destinationLabel": {
            "type": "string"
          },
          "moveType": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": ["planning", "active", "completed", "archived"]
          }
        }
      },
      "MoveSpace": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string"
          },
          "kind": {
            "type": "string"
          },
          "aliases": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "notes": {
            "type": "string"
          },
          "floorLevel": {
            "type": "string"
          },
          "sortOrder": {
            "type": "number"
          }
        }
      },
      "ItemInput": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "itemId": {
            "type": "string"
          },
          "externalSource": {
            "type": "string"
          },
          "externalId": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "room": {
            "type": "string"
          },
          "category": {
            "type": "string"
          },
          "subcategory": {
            "type": "string"
          },
          "disposition": {
            "type": "string",
            "enum": ["keep", "sell", "donate", "free", "dump", "storage", "undecided"]
          },
          "status": {
            "type": "string"
          },
          "quantity": {
            "type": "number"
          },
          "condition": {
            "type": "string"
          },
          "dimensionsIn": {
            "$ref": "#/components/schemas/DimensionsIn"
          },
          "estimatedWeightLb": {
            "type": "number"
          },
          "estimatedWeightLowLb": {
            "type": "number"
          },
          "estimatedWeightHighLb": {
            "type": "number"
          },
          "estimatedVolumeCuFt": {
            "type": "number"
          },
          "estimatedPackedVolumeCuFt": {
            "type": "number"
          },
          "dimensionsConfidence": {
            "$ref": "#/components/schemas/Confidence"
          },
          "weightConfidence": {
            "$ref": "#/components/schemas/Confidence"
          },
          "volumeConfidence": {
            "$ref": "#/components/schemas/Confidence"
          },
          "measurementProvenance": {
            "type": "object"
          },
          "needsReview": {
            "type": "boolean"
          },
          "reviewFlags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "privateNotes": {
            "type": "string"
          },
          "aiSummary": {
            "type": "string"
          },
          "aiTags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "DimensionsIn": {
        "type": "object",
        "properties": {
          "lengthIn": {
            "type": "number"
          },
          "widthIn": {
            "type": "number"
          },
          "heightIn": {
            "type": "number"
          }
        }
      },
      "Confidence": {
        "type": "string",
        "enum": ["none", "low", "medium", "high", "manual", "actual"]
      },
      "SaleListingInput": {
        "type": "object",
        "required": ["itemId"],
        "properties": {
          "itemId": {
            "type": "string"
          },
          "platform": {
            "type": "string",
            "default": "facebookMarketplace"
          },
          "status": {
            "type": "string"
          },
          "listingTitle": {
            "type": "string"
          },
          "listingDescription": {
            "type": "string"
          },
          "askingPriceCents": {
            "type": "number"
          },
          "priceLowCents": {
            "type": "number"
          },
          "priceHighCents": {
            "type": "number"
          },
          "researchDepth": {
            "type": "string"
          },
          "researchSourceCount": {
            "type": "number"
          },
          "researchSources": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "needsMorePhotos": {
            "type": "boolean"
          }
        }
      },
      "PhotoDirectUpload": {
        "type": "object",
        "required": ["moveId"],
        "description": "JSON shape for one-call JPEG, PNG, or WebP upload for agents through /images/upload or /photos/upload. Provide exactly one of sourceUrl, dataUrl, or fileBase64. REST clients with local files can also use multipart/form-data or raw image bytes; MCP clients should use upload_image, upload_photo, or upload_evidence_image with filePath. Set generateAiSuggestions true to queue photo-intake review suggestions after upload.",
        "properties": {
          "moveId": {
            "type": "string"
          },
          "sourceUrl": {
            "type": "string",
            "format": "uri",
            "description": "Public HTTP(S) JPEG, PNG, or WebP URL. Localhost, private-network, and credentialed URLs are rejected."
          },
          "dataUrl": {
            "type": "string",
            "description": "Base64 image data URL such as data:image/jpeg;base64,..."
          },
          "fileBase64": {
            "type": "string",
            "description": "Raw base64 JPEG, PNG, or WebP bytes. Use this for REST clients that read a local image file."
          },
          "fileName": {
            "type": "string"
          },
          "mimeType": {
            "type": "string",
            "enum": ["image/jpeg", "image/png", "image/webp"]
          },
          "itemId": {
            "type": "string"
          },
          "boxId": {
            "type": "string"
          },
          "spaceId": {
            "type": "string"
          },
          "transportResourceId": {
            "type": "string"
          },
          "transportZoneId": {
            "type": "string"
          },
          "room": {
            "type": "string"
          },
          "caption": {
            "type": "string"
          },
          "photoType": {
            "type": "string"
          },
          "privacyLevel": {
            "type": "string"
          },
          "visibilityScope": {
            "type": "string"
          },
          "source": {
            "type": "string",
            "default": "api"
          },
          "confidence": {
            "$ref": "#/components/schemas/Confidence"
          },
          "notes": {
            "type": "string"
          },
          "verificationStatus": {
            "type": "string"
          },
          "capturedAt": {
            "type": "number"
          },
          "generateAiSuggestions": {
            "type": "boolean",
            "description": "When true, queue AI photo-intake suggestions after upload. The queueing step requires inventory/write in addition to photos/write; upload can still succeed if review queueing fails."
          }
        },
        "oneOf": [
          {
            "required": ["sourceUrl"]
          },
          {
            "required": ["dataUrl"]
          },
          {
            "required": ["fileBase64"]
          }
        ]
      },
      "PhotoMultipartUpload": {
        "type": "object",
        "required": ["moveId", "file"],
        "description": "Multipart one-call JPEG, PNG, or WebP upload for REST agents through /images/upload or /photos/upload. Use a file, image, or photo field for the binary image and normal form fields for metadata. Include generateAiSuggestions=true to queue photo-intake review after upload.",
        "properties": {
          "moveId": {
            "type": "string"
          },
          "file": {
            "type": "string",
            "format": "binary",
            "description": "JPEG, PNG, or WebP image file. The field may also be named image or photo."
          },
          "itemId": {
            "type": "string"
          },
          "boxId": {
            "type": "string"
          },
          "spaceId": {
            "type": "string"
          },
          "room": {
            "type": "string"
          },
          "caption": {
            "type": "string"
          },
          "photoType": {
            "type": "string"
          },
          "privacyLevel": {
            "type": "string"
          },
          "visibilityScope": {
            "type": "string"
          },
          "confidence": {
            "$ref": "#/components/schemas/Confidence"
          },
          "notes": {
            "type": "string"
          },
          "verificationStatus": {
            "type": "string"
          },
          "capturedAt": {
            "type": "number"
          },
          "generateAiSuggestions": {
            "type": "boolean",
            "description": "When true, queue AI photo-intake suggestions after upload."
          }
        }
      },
      "PhotoDerivativeVariant": {
        "type": "object",
        "description": "Private storage keys are intentionally omitted. This describes the web-ready derivative variants MovingManifest prepares for display and AI review after an original image upload.",
        "properties": {
          "variant": {
            "type": "string",
            "enum": ["thumb", "card", "detail", "full"]
          },
          "mimeType": {
            "type": "string",
            "example": "image/webp"
          },
          "width": {
            "type": "number",
            "description": "Maximum target width in pixels."
          },
          "height": {
            "type": "number",
            "description": "Maximum target height in pixels."
          },
          "fit": {
            "type": "string",
            "enum": ["cover", "inside", "clientProvided"]
          },
          "status": {
            "type": "string",
            "enum": ["pending", "ready", "failed"]
          }
        }
      },
      "PhotoDirectUploadResponse": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "photoId": {
                "type": "string"
              },
              "uploadSessionId": {
                "type": "string"
              },
              "derivativeStatus": {
                "type": "string",
                "enum": ["ready", "failed"]
              },
              "derivativeError": {
                "type": "string"
              },
              "derivativeNote": {
                "type": "string",
                "description": "Human-readable summary of server-side derivative handling."
              },
              "derivativeVariants": {
                "type": "array",
                "description": "Structured thumb/card/detail/full derivative contract for the uploaded image. It confirms web display variants without exposing private storage keys.",
                "items": {
                  "$ref": "#/components/schemas/PhotoDerivativeVariant"
                }
              },
              "aiReview": {
                "type": "object",
                "description": "Present only when generateAiSuggestions was requested. status is queued when suggestions were created or reused, and failed when upload succeeded but review queueing did not.",
                "properties": {
                  "status": {
                    "type": "string",
                    "enum": ["queued", "failed"]
                  },
                  "aiJobIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "suggestionIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "error": {
                    "type": "string"
                  }
                }
              },
              "media": {
                "type": "object",
                "properties": {
                  "source": {
                    "type": "string",
                    "enum": ["sourceUrl", "dataUrl", "fileBase64"]
                  },
                  "fileName": {
                    "type": "string"
                  },
                  "mimeType": {
                    "type": "string"
                  },
                  "sizeBytes": {
                    "type": "number"
                  },
                  "width": {
                    "type": "number"
                  },
                  "height": {
                    "type": "number"
                  }
                }
              },
              "agentReview": {
                "type": "object",
                "description": "Short assistant-facing summary of the upload choices to tell the user for non-aggressive correction.",
                "properties": {
                  "userFacingSummary": {
                    "type": "string"
                  },
                  "photoId": {
                    "type": "string"
                  },
                  "uploadSessionId": {
                    "type": "string"
                  },
                  "decisions": {
                    "type": "object",
                    "description": "Caption, attachment target, privacy/type choices, confidence, notes, and AI review request used for this upload."
                  },
                  "media": {
                    "type": "object"
                  },
                  "derivativeStatus": {
                    "type": "string"
                  },
                  "derivativeError": {
                    "type": "string"
                  },
                  "derivativeNote": {
                    "type": "string"
                  },
                  "derivativeVariants": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/PhotoDerivativeVariant"
                    }
                  },
                  "aiReviewStatus": {
                    "type": "string"
                  },
                  "aiReview": {
                    "type": "object"
                  },
                  "correctionPrompt": {
                    "type": "string"
                  }
                }
              }
            }
          }
        }
      },
      "UploadInit": {
        "type": "object",
        "required": ["moveId", "mimeType", "sizeBytes"],
        "properties": {
          "moveId": {
            "type": "string"
          },
          "itemId": {
            "type": "string"
          },
          "boxId": {
            "type": "string"
          },
          "room": {
            "type": "string"
          },
          "mimeType": {
            "type": "string"
          },
          "sizeBytes": {
            "type": "number"
          }
        }
      },
      "PhotoFinalize": {
        "type": "object",
        "required": ["moveId", "uploadSessionId"],
        "properties": {
          "moveId": {
            "type": "string"
          },
          "uploadSessionId": {
            "type": "string"
          },
          "width": {
            "type": "number"
          },
          "height": {
            "type": "number"
          },
          "caption": {
            "type": "string"
          },
          "photoType": {
            "type": "string"
          },
          "privacyLevel": {
            "type": "string"
          },
          "visibilityScope": {
            "type": "string"
          },
          "source": {
            "type": "string"
          },
          "verificationStatus": {
            "type": "string"
          }
        }
      }
    }
  }
}
