Task endpoints
All routes below live on tasks_router (prefix /tasks) and require a valid
x-session-token. Paths omit the dev root_path prefix.
POST /tasks/execute
Starts an underwriting process: runs its request step synchronously and enqueues the handle step on SWF.
Request body — an untyped dict, validated in the handler:
{
"task_name": "validate_personal_information",
"task_input": {
"supplier_key": "9b1c4d3e-6f2a-4b8c-9d0e-1f2a3b4c5d6e",
"person_id": "44f2a1b0-7c3d-4e5f-8a9b-0c1d2e3f4a5b",
"first_name": "Jane",
"last_name": "Doe",
"birth_day": "07",
"birth_month": "04",
"birth_year": "1986",
"ssn": "123-45-6789",
"street": "1600 Pennsylvania Avenue",
"city": "Washington",
"state": "DC",
"zip_code": "20500"
},
"force_new_execution": false
}
| Field | Meaning |
|---|---|
|
A process name or a task-step name; resolved by |
|
Process-specific fields; |
|
Truthy values ( |
Behaviour:
-
Permissions — internal callers need
DEV,FINANCEorINT_SUPER_USER. -
Source scoping —
SUPPLIER_DASHBOARDrequests must havetask_input.supplier_key == JWT supplier_key, else400. -
Dedup — an existing non-
failedexecution of the same process whose storedinputequals thistask_inputreturns thatcorrelation_idinstead of starting a new run. -
Rate limit —
SUPPLIER_DASHBOARDis capped at 3 executions per supplier + process →429. -
Source allow-list — the request task’s
get_available_process_sources()decides; otherwise403. -
Input — a missing field raises
KeyError→400naming the field; a failed input validator →400with{"error_class": "ValidationError", "error_body": {"incorrect_fields": {…}}}. -
Workflow already running —
CannotRunWorkflow→400with{"error_class": "CannotRunWorkflow", "error_body": {"reason": …}}("Task already running").
Response — ExecuteTaskResponse:
{ "correlation_id": "3f6c1b64-8f0a-4d2b-9c2e-9f1a5f7c1d22" }
Systems touched: TaskExecutionTable, ToolTable, B2B Task Manager (SWF start).
Special case: reprocess the latest Entrust run
task_name = "entrust/handle_identity_document_validation_response" does not go through the
process machinery — that task has no synchronous request step and is normally fired by the
Onfido webhook. Requested here it becomes an admin reprocess action:
-
Requires
task_input.supplier_keyandtask_input.person_id(missingperson_id→400). -
Internal only —
SUPPLIER_DASHBOARD→403. -
Finds the supplier’s newest
validate_identity_documentrow (bycreate_ts) on thesupplier_key-process_name-indexGSI whoseinputcarries aworkflow_run_idand matchingperson_id, ignoringpurgedrows. Au10tix rows (which carrydocument_id) are skipped. Nothing found →404. -
Force-resets the guards so the rerun really redoes the work:
status→pendinganddocuments_uploaded,documents_approved,uploaded_document_idsare dropped fromadditional_data. -
Re-fires the SWF activity with
task_correlation_id = workflow_run_idand a unique workflow id (… - reprocess - {uuid}) so SWF does not dedup it against the original delivery.CannotRunWorkflow→409.
Response: {"correlation_id": "<workflow_run_id>"}.
|
A reprocess re-archives the run, re-archives every existing identity document, re-uploads the captured files and (on an approved run) re-approves them. Expect a new set of document ids in the supplier’s document store. |
GET /tasks/result
Fetches the outcome of the latest finished execution of a process for one supplier + person.
| Query parameter | Notes |
|---|---|
|
Required. Process name or step name. |
|
Required. |
|
Required. |
|
Optional; only the literal |
-
Internal source only — any other source →
403. -
Selects the newest
processedorfailedexecution for that person (get_latest_processed_task); none →404. -
The final status is read with
get_latest_by_correlation_id, defaulting to{}when absent. -
Unexpected exceptions →
500 {"error_message": "…"}.
Non-detailed response — TaskResult with just the persisted task output:
{ "result": { "raw_result_s3_path": "..." }, "timestamp": "2026-08-12T09:15:11.204812" }
Detailed response additionally reads the archived JSON from S3
(additional_data.full_result_s3_path; a NoSuchKey degrades to {}) and returns status,
final_status, default_result_status and requested_by.
Permission nuance for detailed=true:
| Caller | Result |
|---|---|
Has |
Full payload. |
Lacks them, process is |
Payload returned but masked: everything in |
Lacks them, any other process |
|
Systems touched: TaskExecutionTable, FinalStatusTable, S3.
GET /tasks/{correlation_id}
Polls a single task by its correlation id. Internal source only (403 otherwise).
Response: 200 with {"status": "pending|processed|failed|purged", …task output fields} —
the stored output map is merged into the body. Unknown id → 404; unexpected errors →
500 {"error_message": …}.
Systems touched: TaskExecutionTable.get.
DELETE /tasks/result
Purges archived S3 results for a process (data-deletion / GDPR). Internal source only.
{
"correlation_id": "optional — a fresh uuid4 is used when omitted",
"process_name": "validate_personal_information",
"supplier_key": "9b1c…",
"person_id": "44f2…"
}
process_name, supplier_key and person_id are required (400 otherwise). ProcessFactory
builds both steps of the process, and every step implementing PurgableS3ObjectProducer runs
purge(): each processed execution for that person has its S3 object deleted and its row
marked purged.
Response — DeleteTaskResponse:
{ "correlation_id": "…", "deleted_files": ["thomson_reuters/kyc/supplier_key=…/…json"] }
|
Only the three Thomson Reuters handle tasks implement |
Systems touched: TaskExecutionTable, S3.
PUT /tasks/{correlation_id}/final_statuses
Manual underwriter override of a verdict. Internal source only (403 otherwise).
{ "data": { "DocumentAuthenticity": "VERIFIED", "IDNameMatch": "NOT_VERIFIED", "IsDocumentExpired": "VERIFIED", "OverallQuality": "VERIFIED" } }
Validation (VALIDATION_FIELDS, keyed by the task’s process_name):
| Process | Allowed values | Keys |
|---|---|---|
|
|
|
|
|
|
|
|
Top-level |
download_business_background_report is not overridable (it stores no final status) — its
process_name is rejected with a 400 listing the supported processes.
Behaviour: unknown correlation_id → 404; a validation failure → 400
{"error_message": …}; any other exception → 400. On success the handler saves the final
status if none existed, recomputes the tool status from the override (tiered logic for the
background report, VERIFIED only when no NOT_VERIFIED/NO_MATCH/PENDING value is
present otherwise), updates ToolTable, then updates FinalStatusTable with
updated_by = login_id. Both writes append a changelog row.
Response: 200 {"correlation_id": "…"}.
Systems touched: TaskExecutionTable, FinalStatusTable, ToolTable, ChangelogTable.