{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/signdocs-com-br/json-schema/signdocs-com-br-step-complete-request-schema.json",
  "title": "StepCompleteRequest",
  "description": "Dados para conclusão da etapa. Os campos variam conforme o tipo:\n- `BIOMETRIC_LIVENESS` / `BIOMETRIC_MATCH`: envie `livenessSessionId`.\n- `BIOMETRIC_MATCH` com referência por transação: envie `referenceImage`.\n- Em sandbox: `sandboxSimilarity` simula o score de `BIOMETRIC_MATCH` e `DOCUMENT_PHOTO_MATCH`.\n- `OTP_VERIFY`: envie `code`.\n- `CLICK_ACCEPT`: envie `accepted`.\n- `DOCUMENT_PHOTO_MATCH`: envie `documentImage` e `documentType`.\n- `SERPRO_IDENTITY_CHECK`: envie `cpf`, `name` e `birthDate`.\n",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/signdocs-com-br-openapi.yaml#/components/schemas/StepCompleteRequest",
  "type": "object",
  "properties": {
    "livenessSessionId": {
      "type": "string",
      "description": "ID da sessão de prova de vida (para etapas biométricas)."
    },
    "referenceImage": {
      "type": "object",
      "description": "Imagem de referência por transação para a etapa `BIOMETRIC_MATCH`, usada no lugar\ndo enrollment do usuário. Requer a flag `perTransactionReferenceEnabled` habilitada\nno tenant — caso contrário, 422.\n\nA imagem é validada no envio (exatamente um rosto detectável) e usada apenas nesta\ncomparação: não é armazenada e não cria enrollment. Só o hash SHA-256 fica na\nevidência, em `enrollmentRef.imageHash`, junto de\n`enrollmentRef.capturedFrom: STEP_COMPLETE`.\n\nAceito apenas neste endpoint. Em sessões de assinatura (`POST /v1/signing-sessions`),\nenvie a imagem em `referenceImage.content` na criação da sessão.\n",
      "required": [
        "source",
        "data"
      ],
      "properties": {
        "source": {
          "type": "string",
          "description": "Formato da imagem enviada. Único valor aceito.",
          "enum": [
            "BASE64_IMAGE"
          ]
        },
        "data": {
          "type": "string",
          "format": "byte",
          "description": "Imagem JPEG codificada em base64."
        }
      }
    },
    "sandboxBrightness": {
      "type": "number",
      "format": "double",
      "minimum": 0,
      "maximum": 100,
      "description": "Brilho simulado da captura, para ensaiar a reprovação por qualidade\n(`DOCUMENT_QUALITY_LOW`). Mesmo enquadramento do `sandboxSimilarity`:\nsó vale em sandbox.\n\nAntes destes campos as ramificações de sandbox fixavam 80/80 e nunca\navaliavam o piso de qualidade — ou seja, o erro que mais aparece em\ncampo (luz ruim, reflexo no visor, sujeito em movimento) era o único\nque o integrador não conseguia reproduzir sob demanda.\n"
    },
    "sandboxSharpness": {
      "type": "number",
      "format": "double",
      "minimum": 0,
      "maximum": 100,
      "description": "Nitidez simulada da captura. Ver `sandboxBrightness`.\n"
    },
    "sandboxLivenessConfidence": {
      "type": "number",
      "format": "double",
      "minimum": 0,
      "maximum": 100,
      "description": "Confiança de liveness simulada, para ensaiar a reprovação. Mesmo\nenquadramento do `sandboxSimilarity`: só vale em sandbox, e nunca\naprova uma verificação real.\n\nSubstitui o truque antigo de escrever `fail` no `livenessSessionId`,\nque só produzia 99.5 ou 30.0 — nenhum dos dois perto do limiar, que é\njustamente onde as capturas reais caem. A convenção antiga continua\nvalendo quando nada é informado.\n"
    },
    "sandboxSimilarity": {
      "type": "number",
      "format": "double",
      "minimum": 0,
      "maximum": 100,
      "description": "Similaridade simulada para as etapas `BIOMETRIC_MATCH` e\n`DOCUMENT_PHOTO_MATCH` em sandbox, usada para exercitar o caminho de\nreprovação. Padrão 99.5, que aprova; abaixo do limiar do tenant, a\netapa reprova como reprovaria em produção.\n\nSó é lida com credenciais de sandbox (`credentialMode: SANDBOX`) e\nquando não existe frame real de liveness. Se houve captura real, a\ncomparação real acontece e este campo é ignorado — ele nunca faz uma\ncomparação real passar. Um valor fora de 0-100 ou não numérico\nretorna 400.\n\nNo fluxo de sessões de assinatura, o equivalente é\n`metadata.sandboxSimilarity` na criação da sessão (ou\n`sandboxSimilarity` no corpo do advance, em integrações headless).\n"
    },
    "code": {
      "type": "string",
      "description": "Código OTP de 6 dígitos (para etapa OTP_VERIFY)."
    },
    "accepted": {
      "type": "boolean",
      "description": "Aceite do termo (para etapa CLICK_ACCEPT)."
    },
    "documentImage": {
      "type": "string",
      "format": "byte",
      "description": "Foto do documento codificada em base64 (máx. 5MB). Para etapa `DOCUMENT_PHOTO_MATCH`."
    },
    "documentType": {
      "type": "string",
      "description": "Tipo do documento enviado.",
      "enum": [
        "RG",
        "CNH",
        "PASSPORT",
        "OTHER"
      ]
    },
    "cpf": {
      "type": "string",
      "pattern": "^\\d{11}$",
      "description": "CPF do signatário (para etapa `SERPRO_IDENTITY_CHECK`)."
    },
    "name": {
      "type": "string",
      "description": "Nome completo (para etapa `SERPRO_IDENTITY_CHECK`)."
    },
    "birthDate": {
      "type": "string",
      "format": "date",
      "description": "Data de nascimento no formato `YYYY-MM-DD` (para etapa `SERPRO_IDENTITY_CHECK`)."
    },
    "geolocation": {
      "type": "object",
      "description": "Geolocalização do dispositivo. Obrigatório quando o tenant possui `biometricRequired`\nhabilitado e a etapa é biométrica.\n",
      "properties": {
        "latitude": {
          "type": "number",
          "format": "double",
          "description": "Latitude em graus decimais."
        },
        "longitude": {
          "type": "number",
          "format": "double",
          "description": "Longitude em graus decimais."
        }
      }
    }
  }
}