Schemas

interface/web_api/schemas.py defines the HTTP contract FastAPI uses for validation and OpenAPI generation. The models are intentionally decoupled from the DynamoDB item shapes so storage changes do not leak into the public API.

Response models

class ExecuteTaskResponse(BaseModel):
    correlation_id: str


class DeleteTaskResponse(BaseModel):
    correlation_id: str
    deleted_files: List[str]


class TaskResult(BaseModel):
    result: dict
    timestamp: str
    status: Optional[str] = Field(None)
    final_status: Optional[dict] = Field({})
    default_result_status: Optional[dict] = Field(None)
    requested_by: Optional[str] = Field(None)


class Tool(BaseModel):
    supplier_key: UUID
    person_id: UUID
    type: str
    status: ToolStatus
    name: str
    correlation_id: Optional[UUID] = Field(None)
    updated_by: str
    updated_at: Optional[datetime] = Field(None)
    created_by: str
    created_at: datetime
Model Used by

ExecuteTaskResponse

POST /tasks/execute (including the Entrust reprocess path)

DeleteTaskResponse

DELETE /tasks/result

TaskResult

GET /tasks/result — the optional fields are populated only on a detailed, permitted read

Tool

GET /tools (as List[Tool])

Tool.status is the ToolStatus enum, so an unknown stored value would fail response validation — statuses are always written through the enum.

Entrust models

class CreateEntrustSessionRequest(BaseModel):
    supplier_key: Optional[str] = Field(None)
    person_id: Optional[str] = Field(None)


class EntrustSessionResponse(BaseModel):
    url: str
    workflow_run_id: str
    sdk_token: Optional[str] = Field(None)
    link_expires_at: Optional[str] = Field(None)

Both request fields are optional at the HTTP layer on purpose: supplier-dashboard callers are derived entirely from the JWT and may omit the body, while internal and onboarding callers must supply the target owner. The per-source requirement is enforced inside the handler so the failure is a clear 400 rather than a generic 422.

Untyped bodies

POST /tasks/execute, DELETE /tasks/result and PUT /tasks/{id}/final_statuses accept payload: dict = Body() and validate manually in the handler. That predates the pydantic models above; new endpoints must define a BaseModel instead — see Python standards.

Auth model

components/auth/schemas.py:

class AuthValidateResponse(BaseModel):
    login_id: str
    source: ProcessSource
    login_key: Optional[str] = Field(None)
    supplier_key: Optional[str] = Field(None)

login_id and source come from the auth API response, login_key from the decoded JWT, and supplier_key is present for supplier-dashboard tokens. See Auth & permissions.