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

task_name

A process name or a task-step name; resolved by ProcessFactory.identify_process_name (lower-cased). Also accepts the special Entrust reprocess value — see Special case: reprocess the latest Entrust run.

task_input

Process-specific fields; supplier_key is always required. See Process catalog.

force_new_execution

Truthy values (true, "true", "True", 1, "1") bypass dedup. Internal callers only.

Behaviour:

  • Permissions — internal callers need DEV, FINANCE or INT_SUPER_USER.

  • Source scoping — SUPPLIER_DASHBOARD requests must have task_input.supplier_key == JWT supplier_key, else 400.

  • Dedup — an existing non-failed execution of the same process whose stored input equals this task_input returns that correlation_id instead of starting a new run.

  • Rate limit — SUPPLIER_DASHBOARD is capped at 3 executions per supplier + process → 429.

  • Source allow-list — the request task’s get_available_process_sources() decides; otherwise 403.

  • Input — a missing field raises KeyError → 400 naming the field; a failed input validator → 400 with {"error_class": "ValidationError", "error_body": {"incorrect_fields": {…}}}.

  • Workflow already running — CannotRunWorkflow → 400 with {"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:

  1. Requires task_input.supplier_key and task_input.person_id (missing person_id → 400).

  2. Internal only — SUPPLIER_DASHBOARD → 403.

  3. Finds the supplier’s newest validate_identity_document row (by create_ts) on the supplier_key-process_name-index GSI whose input carries a workflow_run_id and matching person_id, ignoring purged rows. Au10tix rows (which carry document_id) are skipped. Nothing found → 404.

  4. Force-resets the guards so the rerun really redoes the work: status → pending and documents_uploaded, documents_approved, uploaded_document_ids are dropped from additional_data.

  5. Re-fires the SWF activity with task_correlation_id = workflow_run_id and 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

process_name

Required. Process name or step name.

supplier_key

Required.

person_id

Required.

detailed

Optional; only the literal "true" or "True" counts as true.

  • Internal source only — any other source → 403.

  • Selects the newest processed or failed execution 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 DEV, FINANCE, REST_UW_ACCESS or INT_SUPER_USER

Full payload.

Lacks them, process is validate_personal_information

Payload returned but masked: everything in NormalizedCriteria and in each SearchRecord other than FirstName/LastName becomes **.

Lacks them, any other process

403.

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 purge(). Identity-document results (Au10tix and Entrust) are not deleted by this endpoint.

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

validate_personal_information

MATCH, NO_MATCH, PENDING

City, FirstName, LastName, SSN, State, StreetName, StreetNumber, ZipCode, BirthDate, MiddleName, PhoneNumber — every key present in the task’s match_result must be supplied.

validate_identity_document

VERIFIED, NOT_VERIFIED, PENDING

DocumentAuthenticity, IDNameMatch, IsDocumentExpired, OverallQuality — all four required.

download_personal_background_report

PASS, FAIL, ERROR, PENDING

Top-level access / advance, each mapping the seven section names.

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.