DynamoDB tables
Four tables. Names come from settings and are environment-suffixed outside release (see
Settings & secrets reference); the clients that wrap them are described in
AWS clients.
Overview
| Table (setting) | Client | PK | Sort key | Role |
|---|---|---|---|---|
|
|
|
— (GSI |
Async task lifecycle and audit log |
|
|
|
|
Underwriting verdicts per execution |
|
|
|
|
Per-supplier/person tool state |
|
|
|
|
Append-only audit of verdict and tool changes |
task_id and correlation_id are the same value for a given execution.
One correlation_id is created per process execution and is used as:
-
the value returned to the caller by the request step,
-
the
task_idprimary key inTaskExecutionTable, -
the partition key of
FinalStatusTableand thecorrelation_idattribute onToolTable, -
the
task_correlation_idembedded in the SWF workflow input, so the handle step can reload the request.
For Entrust runs the correlation_id is the Onfido workflow_run_id, which is what makes a
redelivered webhook idempotent. Never mint a second correlation id mid-flow.
Task Execution Table
Tracks each execution from creation to completion. Written pending by request tasks (or the
Entrust session endpoint) and updated by handle tasks and the purge flow.
Key: PK task_id. GSI: supplier_key-process_name-index — every list query in the codebase
goes through it and auto-paginates on LastEvaluatedKey.
item = {
'task_id': task_id,
'supplier_key': supplier_key,
'input': input_,
'output': output,
'status': self.PENDING_STATUS,
'process_name': process_name,
'create_ts': datetime.utcnow().isoformat(),
'additional_data': additional_data,
'requested_by': requested_by,
}
if source:
item.update(source=source.value)
update(task_id, item_data) always stamps update_ts and rejects any status outside
TASK_STATUSES with RuntimeError('Status not allowed'). Typical updates add output,
additional_data, default_result_statuses and the S3 result path.
Statuses: pending → processed | failed | purged.
Queries:
| Method | Behaviour |
|---|---|
|
Direct read; raises |
|
GSI query, auto-paginated. |
|
Newest |
|
Newest non- |
Au10tix rows
input = {supplier_key, person_id, document_id}, output = {raw_result_s3_path},
additional_data = {full_result_s3_path}.
Entrust rows
Entrust reuses the validate_identity_document process name (keeping the GSI, dedup and admin
reporting intact) but stores an Entrust-shaped row:
{
"task_id": "b1f7d0c2-3f4e-4a1b-9c8d-2e5f6a7b8c9d",
"supplier_key": "9b1c4d3e-6f2a-4b8c-9d0e-1f2a3b4c5d6e",
"process_name": "validate_identity_document",
"status": "processed",
"source": "onboarding",
"requested_by": "owner@example.com",
"create_ts": "2026-08-12T08:52:44.918002",
"update_ts": "2026-08-12T09:15:12.114900",
"input": {
"supplier_key": "9b1c4d3e-6f2a-4b8c-9d0e-1f2a3b4c5d6e",
"person_id": "44f2a1b0-7c3d-4e5f-8a9b-0c1d2e3f4a5b",
"applicant_id": "c3d4e5f6-a7b8-49c0-8d1e-2f3a4b5c6d7e",
"workflow_run_id": "b1f7d0c2-3f4e-4a1b-9c8d-2e5f6a7b8c9d"
},
"output": {
"raw_result_s3_path": "entrust/identity_document_validation/supplier_key=9b1c.../person_id=44f2.../2026-08-12T09:15:11.204812.json",
"workflow_run_id": "b1f7d0c2-3f4e-4a1b-9c8d-2e5f6a7b8c9d",
"applicant_id": "c3d4e5f6-a7b8-49c0-8d1e-2f3a4b5c6d7e",
"workflow_id": "41aa2ce5-7c0e-4dbe-91c3-12e058a2d1cf",
"status": "approved",
"dashboard_url": "https://dashboard.onfido.com/results/...",
"created_at": "2026-08-12T08:52:45Z",
"updated_at": "2026-08-12T09:14:03Z",
"document_actions": {
"existing_documents_archived": 2,
"id_files_uploaded": 3,
"liveness_files_uploaded": 1,
"uploaded_total": 4,
"approved": 4
}
},
"additional_data": {
"hosted_link": "https://alt.onfido.app/l/eyJhbGciOi...",
"link_expires_at": "2026-08-19T09:14:03Z",
"sdk_token": "eyJhbGciOiJFUzUxMiJ9...",
"documents_uploaded": true,
"uploaded_document_ids": ["7a1b", "7a1c", "7a1d", "7a1e"],
"documents_approved": true,
"document_actions": {
"existing_documents_archived": 2,
"id_files_uploaded": 3,
"liveness_files_uploaded": 1,
"uploaded_total": 4,
"approved": 4
},
"full_result_s3_path": "entrust/identity_document_validation/supplier_key=9b1c.../person_id=44f2.../2026-08-12T09:15:11.204812.json"
}
}
| Attribute | Notes |
|---|---|
|
The Onfido |
|
|
|
Written at session creation; drive the dedup/reuse check. |
|
|
|
The ids the uploads returned, so the approved path can approve exactly that set. |
|
|
|
|
|
Set to the archived run JSON on the terminal update. |
|
On the terminal update: |
A review verdict leaves the row pending (only guards and document_actions are persisted)
until a later completion; a task-level failure sets failed.
Final Status Table
The underwriting verdict for one execution. Every write also appends a changelog row. Multiple
versions per correlation_id are kept, sorted by created_at.
Key: PK correlation_id, sort created_at.
item = {
'correlation_id': correlation_id,
'data': data,
'updated_by': created_by,
'updated_at': current_timestamp,
'created_by': created_by,
'created_at': current_timestamp
}
| Process | data contents |
|---|---|
|
|
|
one key per PII field — |
|
|
|
not written |
| Method | Behaviour |
|---|---|
|
|
|
Reload the first version, replace |
|
The first (oldest) version; raises |
|
The last (newest) version. |
created_by is automatic-uw-tool for automated verdicts, override for the first
manually-created row, and the underwriter’s login_id for updated_by on overrides.
Tool Table
Per-supplier, per-person status of each verification tool. Powers
GET /tools.
Key: PK supplier_key, sort type (the ToolType name).
item = {
'supplier_key': supplier_key,
'person_id': person_id,
'type': tool_type.name,
'status': ToolStatus.NOT_RUN.value,
'correlation_id': correlation_id,
'updated_by': created_by,
'updated_at': current_timestamp,
'created_by': created_by,
'created_at': current_timestamp
}
update() sets status, error_message, correlation_id, updated_by/updated_at and falls
back to save() when the row does not exist (upsert). SUPPORTED_TOOLS — AU10TIX,
ENTRUST, THOMSON_REUTERS_CLEAR_ID, THOMSON_REUTERS_PERSONAL_BACKGROUND_REPORT — is the set
get_tools_and_create_missing / create_missing_tools auto-create for a supplier/person.
|
Because the sort key is |
Status vocabulary and display names: api/tools.adoc#tool-vocabulary.
Changelog Table
Append-only audit trail of every mutation to final-status and tool rows, written automatically
by FinalStatusTable and ToolTable.
Key: PK supplier_key, sort log_ts.
self.__table.put_item(Item={
'supplier_key': supplier_key,
'type': changelog_type.value, # FINAL_STATUS | TOOL
'action': changelog_action.value, # INIT | UPDATE
'data': data, # full snapshot of the row that changed
'log_ts': datetime.utcnow().isoformat(),
'app_version': version.__version__
})
app_version comes from version.py, tying every change to a code version.