Thomson Reuters CLEAR

components/thomson_reuters/client.py wraps the Thomson Reuters CLEAR S2S API: XML over HTTPS with mutual TLS. It backs three processes — KYC, personal background report and business background report.

Contract

Base URL

THOMSON_REUTERS_API_URL — https://s2s.thomsonreuters.com/api in release, https://s2s.beta.thomsonreuters.com/api in dev

Auth

HTTP Basic (THOMSON_REUTERS_USER / THOMSON_REUTERS_PASSWORD) plus a client certificate

Client certificate

PEM cert/key at THOMSON_REUTERS_CERT_FILE_PATH / THOMSON_REUTERS_KEY_FILE_PATH

Payload

Content-type: application/xml; responses parsed with xmltodict.parse()

class ThomsonReutersClient:

    def __init__(self):
        current_directory = os.path.dirname(__file__)
        cert_absolute_path = os.path.join(current_directory, '..', '..', settings.THOMSON_REUTERS_CERT_FILE_PATH)
        key_absolute_path = os.path.join(current_directory, '..', '..', settings.THOMSON_REUTERS_KEY_FILE_PATH)

        self.__cert = (cert_absolute_path, key_absolute_path)
        self.__user = settings.THOMSON_REUTERS_USER
        self.__password = settings.THOMSON_REUTERS_PASSWORD

    def send_request(self, http_method, url, payload=None, query_params=None):
        response = requests.request(
            method=http_method,
            url=url,
            params=query_params,
            data=payload,
            auth=HTTPBasicAuth(self.__user, self.__password),
            headers={'Content-type': 'application/xml'},
            verify=False,
            cert=self.__cert
        )

        response.raise_for_status()

        return xmltodict.parse(response.text)

The paths are resolved relative to the module, so the cert and key must exist on disk before the client is constructed. Where they come from per environment (a PFX bundle in production, ready-made PEMs in dev) is described in Configuration & secrets and Deployment.

verify=False disables server certificate verification while still presenting a client certificate. It suppresses hostname/CA validation against CLEAR — worth knowing about, and worth not copying into new clients.

Request templates

components/thomson_reuters/request_template/ holds one XML template per CLEAR operation, filled by populate_request_template(template_file_name, *kwargs). Every template carries a *PermissiblePurpose block built from settings — THOMSON_REUTERS_PERMISSIBLE_PURPOSE_GLB (B), _DPPA (3), _VOTER (5) — which is the legal basis under which CLEAR data may be pulled.

Template CLEAR operation Used by

clear_id_confirm_person_search.xml

EIDV person search

validate_personal_information (KYC)

background_person_search.xml

Person search v3

download_personal_background_report (locate the person)

background_person_report.xml

Person report

personal background report (the report itself)

background_business_search.xml

Business search

download_business_background_report (locate the business)

background_business_report.xml

Business report

business background report

Endpoints called

Purpose Request

EIDV search

POST /v2/eidvperson/searchResults, then GET the returned Uri

Person search

POST /v3/person/searchResults, then GET the returned Uri

Person report

POST /v2/personReport/reportResults, then poll GET {Uri} while Status.StatusCode == 204

Business search

POST /v2/business/searchResults, then GET the returned Uri

Business report

POST /v2/businessReport/reportResults, then poll GET {Uri} while Status.StatusCode == 204

Namespace handling

CLEAR responses use namespace prefixes (ns2:, ns3:, ns10: …) that are not stable across operations or versions. Two approaches coexist in the codebase:

  • utils/task_utils.py → find_key_in_tr_response(result, key_name, prefix='ns') regex-searches the stringified response for ns<digits>:<KeyName> and raises MalformedResponse when absent. Used by the KYC and personal-report tasks — this is the pattern to follow.

  • The business-report task addresses ns2:/ns3:/ns10:/ns11: literally, with a fallback for the report-details node. A prefix shift there raises KeyError instead of a clean MalformedResponse.

Failure semantics

  • Non-2xx → HTTPError. The KYC task inspects the error body for a CLEAR Status.Message, emits ThomsonReutersNotWorkingEvent, and then fails the task.

  • GroupCount == 0 or a missing count → ResultNotFound.

  • A missing Uri, GroupId or expected node → MalformedResponse.

  • A report that never leaves 204 exhausts the Retry client → RetryException.

  • A personal report missing any of the seven required sections → MissingResponseSection.

Tests

  • Unit: development/unit_tests/task_/thomson_reuters/**.

  • Integration (hits the CLEAR sandbox — run manually, never in CI): development/integration_tests/components_/thomson_reuters/test_client.py.

  • A recorded personal-report response used by test mode and tests: examples/thomson_reuters_personal_background_check_response.json.