{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/easy2257-com/json-schema/easy2257-com-create-upload-session-body-schema.json",
  "title": "CreateUploadSessionBody",
  "x-generated": "2026-11-06",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/easy2257-com-openapi.yml#/components/schemas/CreateUploadSessionBody",
  "type": "object",
  "properties": {
    "contentId": {
      "type": "string",
      "maxLength": 255,
      "description": "Your content id. Echoed back to you on the completion webhook so you can find the row again."
    },
    "contentType": {
      "type": "string",
      "enum": [
        "image",
        "video",
        "gallery"
      ]
    },
    "contentTitle": {
      "type": "string",
      "maxLength": 500
    },
    "detectedFaceCount": {
      "type": "integer",
      "minimum": 0,
      "maximum": 50,
      "description": "How many faces your pipeline detected in the upload. For `captured` content this alone chooses the path: 1 collects a solo attestation, 2 or more opens a collab scene and emails every collaborator the uploader names. For `synthetic` content it is stored for the record and routes nothing, and 0 is allowed. Captured and mixed content need at least 1, since the uploader is in it."
    },
    "contentOrigin": {
      "type": "string",
      "enum": [
        "captured",
        "synthetic",
        "mixed"
      ],
      "description": "What the content is. `captured` (the default when omitted): real people were filmed or photographed. `synthetic`: generated entirely by AI, no real person depicted; the uploader attests to that, no collaborators are invited, and completion fires `upload_session.synthetic_completed`. `mixed`: the uploader with AI-generated figures; the uploader names any other real people, who go through the normal collab flow, and with none named completion fires `upload_session.synthetic_completed`. The uploader cannot change it on the form: if it is wrong, open a new session."
    },
    "personaName": {
      "type": "string",
      "maxLength": 100,
      "description": "The persona the content is posted under, such as an AI persona's display name. Shown on the form and kept with the attestation."
    },
    "contentSha256": {
      "type": "string",
      "pattern": "^[a-fA-F0-9]{64}$",
      "description": "SHA-256 (hex) of the file the uploader is attesting to. Required when `contentOrigin` is `synthetic` or `mixed`; optional for `captured`. Stored lowercased."
    },
    "generationTool": {
      "type": "string",
      "maxLength": 200,
      "description": "What generated the content, at whatever detail you have. `synthetic` and `mixed` only; sending it on `captured` is a `400`. Easy2257 does not take prompts, seeds or source files: the creator keeps those."
    },
    "uploaderExternalUserId": {
      "type": "string",
      "maxLength": 450,
      "description": "Your user id for the uploader. Must already map to an active Easy2257 solo account under your partner account."
    },
    "uploaderEmail": {
      "type": "string",
      "format": "email"
    },
    "uploaderFirstName": {
      "type": "string"
    },
    "uploaderLastName": {
      "type": "string"
    },
    "callbackUrl": {
      "type": "string",
      "format": "uri",
      "description": "Required, stored for your reference. Events go to your portal-registered endpoints."
    },
    "redirectUrl": {
      "type": "string",
      "format": "uri",
      "description": "Required. Where the hosted form returns the uploader when they are done."
    }
  },
  "required": [
    "contentId",
    "contentType",
    "contentTitle",
    "detectedFaceCount",
    "uploaderExternalUserId",
    "uploaderEmail",
    "callbackUrl",
    "redirectUrl"
  ]
}