---
title: "Enrich CRM and wealth platform positions with fund facts"
description: "Attach objective, risk rating, fees and exposure to every fund position in a CRM or PMS. Enrichment pattern, TypeScript example and refresh strategy."
canonical: https://fundfactsapi.com/use-cases/wealth-crm-enrichment
published: 2026-09-04
updated: 2026-09-04
publisher: FundFacts API
---

# Enrich CRM and wealth platform positions with fund facts

> Attach objective, risk rating, fees and exposure to every fund position in a CRM or PMS. Enrichment pattern, TypeScript example and refresh strategy.

Advisers spend their day inside a CRM or portfolio management system, and every position in it is just an ISIN and a quantity. Enriching those positions with fund facts turns a list of codes into something an adviser can talk about with a client. This page shows how to do it and keep it fresh.

## The problem

A CRM or PMS knows what a client holds, but rarely what those holdings are. The position record says `LU0106235293, 1,240 units`. To prepare for a review meeting, the adviser opens a browser, finds the fund house's product page, downloads the factsheet and reads off the risk rating and ongoing charges, for every position, for every client.

Enrichment moves that lookup into the system. When a position appears, the platform attaches the fund's key facts to it and refreshes them on a schedule, so the adviser sees the risk rating and fees next to the holding without leaving the record.

## What you need from the data

Enrichment fields should be short, stable and safe to display. The typical set:

- Fund name and share class, to confirm the position matches the intended class
- Asset class, sub-asset and region focus, for grouping a client's book
- Risk rating 1–7, for a quick suitability sanity check
- TER or ongoing charges, for cost conversations
- Distribution policy and currency, for income and FX questions
- Fund manager and benchmark name
- The as-of date of the source documents

Deep data such as the top holdings and performance series belongs in a drill-down, not the position list. See [portfolio look-through](https://fundfactsapi.com/use-cases/portfolio-look-through) for that layer.

## How it works with FundFacts API

Most platforms expose a webhook or a scheduled job hook. The pattern is: on position create, and nightly for positions whose data has expired, call the API and write a compact enrichment record back to the platform's custom fields.

```typescript
type Enrichment = {
  isin: string;
  name: string;
  assetClass?: string;
  regionFocus?: string;
  riskRating?: number;
  ter?: number;
  distribution?: string;
  currency?: string;
  manager?: string;
  benchmark?: string;
  dataAsOf?: string;
  expiresAt: string;
};

export async function enrich(isin: string): Promise<Enrichment | null> {
  const res = await fetch(`https://fundfactsapi.com/api/v1/funds/${isin}`, {
    headers: { Authorization: `Bearer ${process.env.FUNDFACTS_API_KEY}` },
  });
  if (res.status === 404) return null; // not a fund we can describe
  if (!res.ok) throw new Error(`${res.status} loading ${isin}`);
  const { name, data, expiresAt } = await res.json();
  return {
    isin,
    name,
    assetClass: data.keyFacts?.assetClass,
    regionFocus: data.profile?.regionFocus,
    riskRating: data.riskRating,
    ter: data.headlineMetrics?.ter,
    distribution: data.keyFacts?.distribution,
    currency: data.keyFacts?.currency,
    manager: data.keyFacts?.manager,
    benchmark: data.benchmarkName,
    dataAsOf: data.dataAsOf,
    expiresAt,
  };
}
```

Write the result to the platform's custom fields (most CRMs allow a dozen or so per object) and store `expiresAt` in one of them so the refresh job knows what to re-load.

## Design notes

**Not every ISIN is a fund.** Client books contain single stocks, bonds and structured products. The API returns `404 fund_not_found` for those; treat it as "no enrichment", not as an error, and do not retry it nightly.

**Caching.** Data refreshes every 24 hours. Enrich once per ISIN, not once per position: a popular fund held by two hundred clients is one request. Re-load only when `expiresAt` has passed, and only for ISINs still held by at least one client.

**Quota.** A wealth firm's distinct-ISIN count is usually in the hundreds, which fits a Pro or Scale plan on a daily refresh. Check `X-RateLimit-Remaining` in the job and spread the work across the day if you are close to the limit. On `429`, wait for `X-RateLimit-Reset`.

**Field mapping.** CRMs often restrict custom-field types. Store `riskRating` as a number, `ter` as a number in percent and `dataAsOf` as a date, so advisers can filter and sort on them.

**Disclaimers.** Enriched facts are read from the documents each fund house publishes and shown for information. Display `dataAsOf` next to the figures, and keep any suitability judgement in the adviser's hands and the firm's process. The enrichment is input, not advice.

For the identifiers you will meet in position data, see [what is an ISIN](https://fundfactsapi.com/blog/what-is-an-isin), and for the fee figure, [ongoing charges](https://fundfactsapi.com/glossary/ongoing-charges).

## FAQ

### What happens when a position's ISIN is a stock or a bond rather than a fund?

The API describes funds and ETFs only, so a single stock, government bond or structured note returns 404 fund_not_found with reason not_a_fund, which is not counted. Record that outcome against the ISIN so your job does not retry it every night. Showing the position without enrichment is the correct result; it is not a data error.

### How often should the enrichment refresh?

Once a day is enough. The API re-reads each fund's published documents on a 24-hour cycle and tells you the exact moment via expiresAt, so a nightly job that reloads only expired ISINs keeps every position current. Risk ratings, fees and objectives change infrequently, and a daily cadence catches those changes within a day of publication.

### Can I use the same enrichment for the client-facing portal?

Yes, the fields are suitable for display, with two additions. Show dataAsOf beside the figures so clients know the effective date, and include a not-investment-advice statement. The investmentObjective text is written by the fund house and can be shown verbatim; avoid adding any commentary that reads as a recommendation.

### Which identifier should the CRM store?

The share-class ISIN. Fund names are ambiguous because one fund can have many share classes with different currencies, distribution policies and fee levels, and tickers vary by exchange. If your custodian feed supplies SEDOL or WKN instead, map them to ISINs before enrichment so the API returns the exact class the client holds.

## About FundFacts API

FundFacts turns any fund or ETF ISIN into one dated factsheet (fees and KID costs, the 1–7 risk indicator, holdings, sector and country exposure, returns) read from the fund house's own documents: as a client-ready PDF under your firm's name for advisers and wealth managers, as JSON through its API for developers, or inside ChatGPT and Claude through its MCP server.

FundFacts works inside ChatGPT and Claude as a connector (a remote MCP server): ask about any fund or ETF by ISIN, ticker or name and the assistant answers from FundFacts' dated figures, fees, risk, holdings, exposure and returns, with fund cards, side-by-side comparisons, holdings overlap and portfolio look-through.

- Free API key, no card: https://fundfactsapi.com/signup
- Documentation: https://fundfactsapi.com/docs (OpenAPI: https://fundfactsapi.com/openapi.json)
- MCP server: https://fundfactsapi.com/api/mcp (set-up for every client: https://fundfactsapi.com/mcp-server)
- Pricing: https://fundfactsapi.com/pricing
- Site index for AI assistants: https://fundfactsapi.com/llms.txt
- Informational data, not investment advice.
