Bloomberg Enrich and Sync
Search in Bloomberg, enrich in Dark Matter, and sync to CRM workflow.
Overview
This cookbook walks through a complete research-to-operations pipeline: Bloomberg → Dark Matter → CRM. You search for positions of interest in Bloomberg (terminal or API), enrich them in Dark Matter with registry data, compliance status, and transfer restrictions, then sync the enriched data to your CRM. The pattern applies to allocators, fund administrators, and secondary market desks who need to reconcile Bloomberg holdings with Dark Matter's canonical registry and push structured data into Salesforce, HubSpot, or other CRM systems.
Step 1: Search Bloomberg
Use the Bloomberg terminal or Bloomberg API to search for positions of interest. Extract entity identifiers, issuer names, fund names, or other search criteria that you can use in the next step. The output feeds into Dark Matter enrichment.
Bloomberg API setup and search syntax depend on your Bloomberg Data License or B-PIPE subscription. Consult your Bloomberg representative for API access. For terminal-only workflows, export search results (e.g., CSV) and use issuer names or identifiers to query Dark Matter.
Step 2: Enrich in Dark Matter
Pass the Bloomberg results to the DMTR API for enrichment. Use the positions search endpoint to match entities by issuer name and retrieve full Position Objects. Dark Matter adds compliance status, transfer restrictions, valuation, vehicle class, and other canonical fields not available in Bloomberg.
const results = await dmtr.positions.search({ issuer_name: "Acme Growth Fund III" });
for (const pos of results.data) {
console.log(pos.entity_id, pos.asset?.issuer?.name, pos.valuation?.current_mark?.value);
}{
"data": [
{
"entity_id": "meg-2026-112",
"owner": "part-allocator-001",
"status": "active",
"asset": {
"vehicle_class": "fund_lp",
"issuer": {
"name": "Acme Growth Fund III",
"jurisdiction": "US-DE"
},
"terms_hash": "sha256:abc123..."
},
"valuation": {
"current_mark": {
"value": 2500000,
"currency": "USD",
"as_of": "2026-03-01",
"provenance": "gp_mark"
},
"cost_basis": 2100000
},
"transfer": {
"transferable": true,
"restrictions": [
{
"type": "lockup",
"expires": "2027-01-15T00:00:00Z"
},
{
"type": "rofr"
},
{
"type": "consent_required"
}
]
},
"compliance": {
"kyc_status": "cleared",
"aml_status": "cleared",
"accreditation_required": true
}
}
],
"has_more": false
}Step 3: Map to CRM schema
Map the enriched Position Objects to your CRM schema. Each CRM has different field names and data models; the table below shows a typical mapping from Dark Matter fields to common CRM equivalents.
| Property | Type | Required | Description | Example |
|---|---|---|---|---|
| entity_id | Position__c.ExternalId__c | Yes | Unique position identifier; use as external ID for upserts and deduplication. | — |
| asset.issuer.name | Account.Name | Yes | Issuer or fund name; map to Account or Contact depending on CRM model. | — |
| asset.vehicle_class | Position__c.VehicleClass__c | No | fund_lp, spv_llc, doiv_membership_interest, direct; use for filtering and reporting. | — |
| valuation.current_mark.value | Position__c.ValuationAmount__c | No | Current mark-to-market value; may require currency conversion. | — |
| status | Position__c.Status__c | Yes | active, registered, encumbered, transferred; drives CRM lifecycle. | — |
| transfer.transferable | Position__c.Transferable__c | No | Boolean; indicates if position can be offered on secondary market. | — |
| transfer.restrictions | Position__c.Restrictions__c | No | lockup, rofr, gp_consent; store as multi-select or JSON. | — |
| compliance.kyc_status | Contact.KYCStatus__c | No | cleared, pending, failed; map to contact or deal record. | — |
Step 4: Sync to CRM
Push the mapped data to your CRM via its API. Use upsert semantics keyed by entity_id (or your CRM external ID) to avoid duplicates. Include an idempotency key when your CRM or proxy supports it.
const results = await dmtr.positions.search({ issuer_name: "Acme Growth Fund III" });
for (const pos of results.data) {
await crmClient.upsert({
object: "Position__c",
externalId: pos.entity_id,
data: {
ExternalId__c: pos.entity_id,
IssuerName__c: pos.asset?.issuer?.name,
VehicleClass__c: pos.asset?.vehicle_class,
ValuationAmount__c: pos.valuation?.current_mark?.value,
Status__c: pos.status,
Transferable__c: pos.transfer?.transferable
}
});
}Use idempotency keys for CRM sync operations. If your CRM API supports Idempotency-Key, send a deterministic key (e.g., hash of entity_id + version) so retries do not create duplicate records. See Idempotency for Dark Matter's approach.
Related docs
- Pagination — Cursor-based pagination when syncing large result sets
- Idempotency — Idempotency keys for safe retries