Skip to content

Client

client

Synchronous yente / OpenSanctions client.

BEST_ALGORITHM module-attribute

BEST_ALGORITHM: Final[str] = 'best'

Canonical algorithm name resolving to whichever matching algorithm the server currently recommends. Stable across algorithm version bumps — pass algorithm=BEST_ALGORITHM for forward-compatibility.

Client

Client(
    *,
    api_key: str | None = None,
    base_url: str = DEFAULT_BASE_URL,
    app_name: str | None = None,
    user_agent: str | None = None,
    timeout: float | Timeout | None = None,
    verify: bool | str = True,
    proxy: str | None = None,
    headers: dict[str, str] | None = None,
    transport: BaseTransport | None = None,
)

Synchronous client for the yente / OpenSanctions API.

Use as a context manager for deterministic cleanup of the underlying httpx.Client.

user_agent property

user_agent: str

Return the User-Agent header this client sends on every request.

adjacent

adjacent(
    entity_id: str,
    *,
    prop: None = None,
    limit: int | None = None,
    offset: int = 0,
    sort: list[str] | None = None,
) -> AdjacentResponse
adjacent(
    entity_id: str,
    *,
    prop: str,
    limit: int | None = None,
    offset: int = 0,
    sort: list[str] | None = None,
) -> AdjacentPropertyResponse
adjacent(
    entity_id: str,
    *,
    prop: str | None = None,
    limit: int | None = None,
    offset: int = 0,
    sort: list[str] | None = None,
) -> AdjacentResponse | AdjacentPropertyResponse

Fetch the adjacency map for an entity, optionally restricted to one property.

Without prop: returns the full adjacency map keyed by property name. With prop: returns paginated results for that one property.

algorithms

algorithms() -> AlgorithmsResponse

Fetch the list of enabled matching algorithms and the server's defaults.

close

close() -> None

Close the underlying httpx.Client.

datasets

datasets() -> DatasetsResponse

Fetch the indexed datasets and their freshness state.

Calls the wire endpoint GET /catalog; the SDK surface uses the datasets name because that's what the response carries. Revalidates via ETag when the server provides one (yente doesn't yet; see opensanctions/yente#1202).

fetch

fetch(entity_id: str, *, nested: bool = True) -> Entity

Fetch a single entity by ID.

Follows 308 redirects transparently when entity_id is a referent of a canonical entity. Pass nested=False for a lighter response that omits adjacent entities like sanctions and ownership links.

healthz

healthz() -> StatusResponse

Probe server liveness.

Returns {"status": "ok"} whenever the server process is up. Useful for Kubernetes liveness probes. See :meth:readyz for index readiness, which can fail independently.

match

match(
    entity: EntityInput,
    *,
    filters: MatchFilters | None = None,
    threshold: float | None = None,
    cutoff: float | None = None,
    algorithm: str | None = None,
    weights: dict[str, float] | None = None,
    config: dict[str, Any] | None = None,
    limit: int | None = None,
    **filter_kwargs: Any,
) -> MatchResponse

Match an entity against a dataset by example.

Builds a single-query payload and unwraps the response into a flat :class:MatchResponse.

Pass filter fields either via filters=MatchFilters(...) or as kwargs (datasets=[...], topics=[...], exclude_entities=[...]); kwargs win on any field they specify.

Parameters:

Name Type Description Default
threshold float | None

Score at or above which a result's match flag is set (server default 0.70). Does not remove results.

None
cutoff float | None

Score below which candidates are dropped from the response entirely (server default 0.50).

None
algorithm str | None

Server-side algorithm name. Common values: "best" (use BEST_ALGORITHM), "logic-v2", "name-matcher". The full set is dynamic via :meth:algorithms.

None

Raises:

Type Description
ConfigurationError

entity's schema is not a matchable target (e.g. Document, Article). Yente would reject the query with a 4xx; the client refuses it before the round-trip to give a clearer error.

match_iter

match_iter(
    entities: Iterable[tuple[str, EntityInput]],
    *,
    workers: int = 4,
    filters: MatchFilters | None = None,
    threshold: float | None = None,
    cutoff: float | None = None,
    algorithm: str | None = None,
    weights: dict[str, float] | None = None,
    config: dict[str, Any] | None = None,
    limit: int | None = None,
    on_error: Literal["raise", "collect"] = "raise",
    **filter_kwargs: Any,
) -> Iterator[tuple[str, MatchResponse | MatchError]]

Stream /match calls over many entities with bounded concurrency.

The batch-screening primitive: feed any iterable of (key, entity) pairs — a lazy generator over a file works — and results stream back as (key, response) pairs with at most workers requests in flight. New work is only pulled from the iterable as results are consumed, so memory stays flat regardless of input size. One entity per request by design; there is no wire-level batching.

Parameters:

Name Type Description Default
entities Iterable[tuple[str, EntityInput]]

(key, entity) pairs. Results arrive in completion order, not input order — the key ties a result back to its input row.

required
workers int

Maximum concurrent requests.

4
on_error Literal['raise', 'collect']

"raise" (default) aborts the stream on the first failed item. "collect" yields (key, MatchError) for the failed item and keeps going — use for long runs that must survive individual failures.

'raise'

Yields:

Type Description
str

(key, MatchResponse) per input pair; with

MatchResponse | MatchError

on_error="collect", failed pairs surface as

tuple[str, MatchResponse | MatchError]

(key, MatchError) instead.

programs

programs() -> ProgramsResponse

Fetch the sanctions-program catalog — resolves programId codes.

Sanctioned entities carry a programId property naming the program under which they were designated (e.g. "EU-UKR"); this catalog maps those codes to the program's title, issuer, policy summary, and measures. Fetched from :data:PROGRAMS_URL on the public OpenSanctions data bucket — an absolute URL, so it works regardless of base_url (including against a self-hosted yente). Long-lived clients revalidate via ETag: repeat calls cost a bodiless 304 round-trip, not the full artifact.

readyz

readyz() -> StatusResponse

Probe whether the search index is ready to serve queries.

Returns the same shape as :meth:healthz, but the server returns 503 (mapped to :class:ServerError) until the index is loaded.

search

search(
    q: str,
    *,
    filters: SearchFilters | None = None,
    limit: int | None = None,
    offset: int = 0,
    sort: list[str] | None = None,
    fuzzy: bool = False,
    simple: bool = False,
    facets: list[str] | None = None,
    **filter_kwargs: Any,
) -> SearchResponse

Run a full-text search across one or more datasets.

Pass filter fields either via filters=SearchFilters(...) or as kwargs (datasets=[...], schema=, countries=[...], …); kwargs win on any field they specify. The datasets filter is translated to the v1 wire as /search/<first-dataset> with the rest passed as repeated include_dataset query params.

statements

statements(
    *,
    dataset: str | None = None,
    entity_id: str | None = None,
    canonical_id: str | None = None,
    prop: str | None = None,
    value: str | None = None,
    schema: str | None = None,
    sort: list[str] | None = None,
    limit: int | None = None,
    offset: int = 0,
) -> StatementsResponse

Read raw entity data as statements — for lineage and diagnostics.

Use this for tracking where a value came from, when it was first observed, and which dataset asserted it. See the statement-based data model <https://www.opensanctions.org/docs/statements/>_ for context.

Typically you want canonical_id=, passing the ID returned by :meth:match / :meth:search / :meth:fetch. It returns every source fragment that was deduplicated into the canonical entity. entity_id= returns only one source's pre-deduplication fragment — useful for source-level audits, but the same person across five sanctions lists has five distinct entity_id values and only one canonical_id.

Only the OpenSanctions API serves this endpoint — it is backed by a Postgres instance that yente doesn't ship. A yente instance returns 404, which surfaces here as :class:NotFoundError with a pointed message.

Parameters:

Name Type Description Default
dataset str | None

Restrict to statements from this dataset.

None
entity_id str | None

Filter by the source entity ID (e.g. "ofac-1234"). Pre-deduplication; usually not what you want — prefer canonical_id.

None
canonical_id str | None

Filter by the post-deduplication entity ID (e.g. "NK-1234"). The typical choice.

None
prop str | None

Filter by property name (e.g. "alias").

None
value str | None

Filter by exact property value.

None
schema str | None

Filter by entity schema (e.g. "LegalEntity").

None
sort list[str] | None

Sort keys; defaults to ["canonical_id", "prop"].

None
limit int | None

Page size; server-capped (typically at 5000).

None
offset int

Pagination offset.

0