Skip to main content
The shortest path between “I have a list of names/emails” and “I have full profiles” isn’t a single call to enrich. It’s a two-step pattern:
  1. /resolve — match your records to Minerva PIDs.
  2. /enrich — fetch profiles, keyed only by the PIDs from step 1.
The second call skips our match pipeline entirely (we already know who they are), so it’s faster and cheaper than re-running the whole enrich-by-PII flow. For pipelines that re-process the same person list periodically (monthly hygiene refresh, segment re-materialization, customer data activation), step 1 only needs to run once — cache the PIDs and call enrich directly on subsequent runs. mc.workflows.resolve_then_enrich is the encoded version of step 1 + 2:
from minerva import Minerva

mc = Minerva()
result = mc.workflows.resolve_then_enrich(
    records=[
        {"record_id": "u1", "emails": ["a@example.com"]},
        {"record_id": "u2", "emails": ["b@example.com"]},
        {"record_id": "u3", "full_name": "Some Person"},
    ],
)

result.resolved              # list[ResolveResult] — PIDs (or None for unmatched)
result.enriched              # list[EnrichResult]  — full profiles, keyed by PID
result.unmatched_record_ids  # list[str]           — record_ids that didn't match
The async sibling is await mc.workflows.resolve_then_enrich(...) on an AsyncMinerva client; same shape.

What it does for you

  • Validates the resolve request locally (raises MinervaValidationError before any HTTP call).
  • Splits the resolve results into “matched” + “unmatched” so you don’t have to filter manually.
  • Builds the enrich payload from the matched PIDs only — your original fields (emails, names, etc.) don’t get sent on the second call, and the server takes the fast path.
  • Skips the enrich call entirely if no records resolved (saves a round-trip
    • your daily quota).

When to use it vs. mc.api.enrich directly

You have…Use
Names/emails/phones, want profilesmc.workflows.resolve_then_enrich(records)
Already-known Minerva PIDs (e.g. from a prior run)mc.api.enrich(records) with minerva_pid per record
LinkedIn URLsmc.api.enrich(records) — direct lookup, no resolve needed

Caching the resolved PIDs

If your workflow repeats (e.g. nightly), cache the result.resolved list and short-circuit step 1 on the next run:
# First run: full pipeline
result = mc.workflows.resolve_then_enrich(records)
cache.save({r.record_id: r.minerva_pid for r in result.resolved if r.minerva_pid})

# Subsequent runs: enrich by PID directly
known_pids = cache.load()
enrich_resp = mc.api.enrich(
    [{"record_id": rid, "minerva_pid": pid} for rid, pid in known_pids.items()]
)
That second pattern is what the server is most optimized for — single round trip, no match pipeline, just a profile lookup.