Skip to content
Dark MatterDark Matter
Cookbook

PitchBook Inventory Mapping

Map PitchBook entities to DMTR inventory for unified portfolio view.

Overview

PitchBook and DMTR use different entity models. PitchBook organizes data around deals, companies, and funds—transaction-centric structures built for research and deal flow. DMTR organizes around positions (ownership interests) and registry entities—canonical records for transfer, compliance, and lifecycle. This cookbook explains how to map PitchBook entities to DMTR inventory so you can build a unified portfolio view, reconcile research data with operational positions, and enable cross-platform workflows.

The mapping problem is non-trivial: a single PitchBook deal may correspond to multiple DMTR positions (e.g., different LPs in the same fund), and a company may map to multiple issuers or vehicles in DMTR. Understanding the cardinality and building a robust mapping layer is essential before syncing or reporting.

Entity model comparison

The table below shows how key PitchBook fields map to DMTR equivalents. Use this as a reference when building your mapping logic.

PropertyTypeRequiredDescriptionExample
deal_identity_idNoPitchBook deal identifier. Maps to one or more DMTR position entity_ids; cardinality is many-to-one (multiple deals can reference same position) or one-to-many (one deal to multiple positions).—
company_nameissuer_nameYesPitchBook company or fund name. Primary field for fuzzy matching against DMTR issuer_name; handle legal vs DBA variations.—
fund_nameissuer_name / vehicle_classNoPitchBook fund name. Maps to DMTR issuer_name for fund_lp positions; vehicle_class distinguishes fund_lp, spv_llc, direct.—
investor_nameparticipant_idNoPitchBook investor or LP name. Maps to DMTR participant_id; may require participant lookup by name.—
deal_sizevaluation_amountNoPitchBook deal size (USD). Maps to DMTR valuation.current_mark or valuation_amount; may need currency conversion.—
deal_typeposition_typeNoPitchBook deal type (e.g., PE, VC, growth). Maps to DMTR position_type or asset.vehicle_class for filtering.—
close_dateeffective_dateNoPitchBook deal close date. Maps to DMTR effective_date or position creation timestamp.—
geographyjurisdictionNoPitchBook geography or region. Maps to DMTR jurisdiction; use for compliance and transfer eligibility checks.—

Step 1: Export from PitchBook

Export your PitchBook data in a format suitable for mapping. You can use the PitchBook API (if available under your subscription) or CSV export from the terminal.

PitchBook API access and search syntax depend on your subscription. Consult your PitchBook representative for API credentials and rate limits. For terminal-only workflows, export search results (e.g., CSV) and use company names, deal IDs, or fund names to query DMTR. The mapping logic below works with either source.

Extract at minimum: deal ID, company/fund name, investor name, deal size, deal type, close date, and geography. These fields feed into the mapping and enrichment steps.

Step 2: Build the mapping

Create a mapping function that takes a PitchBook entity and searches DMTR for matches. Use issuer name as the primary key for fuzzy matching; handle legal name variations, abbreviations, and common suffixes (e.g., "LP", "LLC").

import { DmtrClient } from "@dmtr/sdk";

const dmtr = new DmtrClient({ apiKey: process.env.DMTR_API_KEY });

async function mapPitchBookToDmtr(pitchbookDeal: {
  deal_id: string;
  company_name: string;
  fund_name?: string;
}) {
  const searchName = pitchbookDeal.fund_name ?? pitchbookDeal.company_name;
  const results = await dmtr.positions.search({ issuer_name: searchName });

  if (results.data.length === 0) {
    return { mapped: false, candidates: [] };
  }

  const candidates = results.data.map((pos) => ({
    entity_id: pos.entity_id,
    issuer_name: pos.asset?.issuer,
    match_score: fuzzyScore(searchName, pos.asset?.issuer ?? ""),
  }));
  candidates.sort((a, b) => b.match_score - a.match_score);

  return {
    mapped: candidates.length > 0,
    pitchbook_deal_id: pitchbookDeal.deal_id,
    dmtr_candidates: candidates,
  };
}

function fuzzyScore(a: string, b: string): number {
  const na = a.toLowerCase().replace(/\s+/g, " ");
  const nb = b.toLowerCase().replace(/\s+/g, " ");
  return na === nb ? 1 : na.includes(nb) || nb.includes(na) ? 0.8 : 0;
}

The mapping returns candidates ranked by a simple fuzzy score. For production, consider using a dedicated fuzzy matching library (e.g., fuse.js, rapidfuzz) or embedding-based similarity.

Step 3: Enrich and validate

Once you have candidate DMTR entity IDs, fetch the full position objects to enrich your data and validate the match. Use the positions get endpoint or search with filters.

async function enrichFromDmtr(entityId: string) {
  const position = await dmtr.positions.get(entityId);
  return {
    entity_id: position.entity_id,
    issuer: position.asset?.issuer,
    vehicle_class: position.asset?.vehicle_class,
    valuation: position.valuation?.current_mark,
    status: position.status?.current,
    transferable: position.transfer?.transferable,
    restrictions: position.transfer?.restrictions,
  };
}
200Success
{
  "entity_id": "meg-2026-112",
  "issuer": "Acme Growth Fund III",
  "vehicle_class": "fund_lp",
  "valuation": 2500000,
  "status": "active",
  "transferable": true,
  "restrictions": [
    "lockup",
    "rofr",
    "gp_consent"
  ]
}

Compare the enriched DMTR data with your PitchBook record. Validate that deal size aligns with valuation, geography matches jurisdiction, and investor/participant is consistent before persisting the mapping.

Step 4: Reconciliation

Run a reconciliation script periodically to find unmapped entities. Iterate over your PitchBook export and DMTR inventory; flag deals with no mapping and positions with no PitchBook counterpart.

async function findUnmappedPitchBookDeals(
  pitchbookDeals: Array<{ deal_id: string; company_name: string }>,
  mappingTable: Map<string, string>
) {
  const unmapped: string[] = [];
  for (const deal of pitchbookDeals) {
    if (!mappingTable.has(deal.deal_id)) {
      unmapped.push(deal.deal_id);
    }
  }
  return unmapped;
}

async function findUnmappedDmtrPositions(participantId: string) {
  const allPositions: string[] = [];
  for await (const pos of dmtr.positions.listIter({ participant_id: participantId })) {
    allPositions.push(pos.entity_id);
  }
  return allPositions;
}

Flag unmapped entities for manual review. Use webhooks to trigger real-time reconciliation when DMTR positions change. See Pagination for cursor-based iteration over large inventories.

Many-to-many cardinality: One PitchBook deal can map to multiple DMTR positions (e.g., multiple LPs in the same fund). Conversely, one DMTR position may be referenced by multiple PitchBook deals (e.g., different rounds or research records). Design your mapping table to support many-to-many relationships and avoid overwriting valid mappings when syncing.

Edit this page on GitHub

Last reviewed: March 13, 2026

Was this page helpful?