← Back to blog

UK Director Dealings API: PDMR Filings from the FCA's NSM in Python

Filip Stanczyk · · 4 min read

UK directors still report their share dealings under the Market Abuse Regulation. After Brexit the UK kept MAR as onshored law ("UK MAR"), and the FCA enforces it through DTR 3.1.4. A director, or a person closely associated with one, notifies the company within three business days, and the company publishes the notification as a regulatory announcement. The FCA archives every such announcement in the National Storage Mechanism (NSM).

So the data is public. It is not convenient.

What the NSM gives you

The NSM is a document archive. Director dealings are announcements of the type "Director/PDMR Shareholding". Each is a page of text: usually the MAR notification template, sometimes a press release, sometimes both.

To turn that into data you have to:

  • Find the announcements. The NSM website has a search, but no documented API. Over 117,000 director-dealing announcements sit in the archive.
  • Parse free text. The template is common, but each news service and issuer renders it differently. We have seen the transaction section labelled at least eight different ways, dates written as 2026.09.22, 22nd September 2026 and September 22, 2026, and prices given in pounds, pence ("250p") or US dollars.
  • Check the numbers. Section 4(d) of the template restates the aggregated volume and the weighted price. It is the filing's own check figure, and it catches errors: a summary row read as a second trade, a price in pence read as pounds, four directors' volumes run together into one number.
  • Handle dates that can't be read either way. Some US-incorporated issuers file in the UK, so 07/09/2026 could be 7 September or 9 July. Unless the filing settles it elsewhere, the only honest answer is to refuse the date, not guess.

Without those checks, one filing listing four people's volumes separated by spaces reads as a single purchase of 394 million shares. Our own parser made that mistake before the checks existed.

The same data as JSON

Duceus reads every UK director-dealing announcement, parses the template, checks the figures against the filing's own aggregate and stores the result in one schema shared with 17 other European registers. A filing that fails the check is refused rather than stored with a guess.

curl "https://api.duceusapi.com/transactions?country=GB&limit=3" \
  -H "Authorization: Bearer YOUR_API_KEY"

In Python, with only requests:

import os
import requests

API = "https://api.duceusapi.com"
HEADERS = {"Authorization": f"Bearer {os.environ['DUCEUS_API_KEY']}"}

response = requests.get(
    f"{API}/transactions",
    headers=HEADERS,
    params={"country": "GB", "transaction_type": "BUY", "limit": 50},
    timeout=30,
)
response.raise_for_status()

for deal in response.json()["items"]:
    price = deal["unit_price"]
    if deal["currency"] == "GBX":  # pence: divide by 100 for pounds
        price = price / 100
    print(
        deal["published_at"][:10],
        deal["issuer_name"],
        deal["person_role"],
        deal["volume"],
        price,
    )

Fields worth knowing

Field What it holds
person_role The role at the time of the deal, in buckets: CEO, CFO, CHAIR, BOARD_MEMBER, EXECUTIVE, CLOSELY_ASSOCIATED, OTHER
person_position The filing's own wording, e.g. "Member of the Executive Committee"
transaction_type Normalized nature: BUY, SELL, SHARE_AWARD, OPTION_EXERCISE…
transaction_type_raw The filing's own wording, e.g. "Grant of options under the 2026 Sharesave Plan"
currency ISO code. UK prices in pence come back as GBX, not GBP
unit_price Null when the consideration isn't one price per unit, never a guessed figure
source_url The announcement on the NSM

The UK has a lot of plan activity: Sharesave grants, SIP partnership and matching shares, dividend reinvestment. A scheduled plan purchase is classified as SHARE_AWARD and a reinvested dividend as DIVIDEND_IN_KIND, so transaction_type=BUY keeps only discretionary market purchases.

Filtering to one company

By ticker, LEI or ISIN:

curl "https://api.duceusapi.com/transactions?lei=213800ZVIELEA55JMJ32" \
  -H "Authorization: Bearer YOUR_API_KEY"

/issuers/{id}/insider-activity gives the aggregate view for one company: net buying over 30, 90 and 180 days, and whether a cluster buy (three or more insiders buying within 30 days) is under way.

What we don't cover yet

About four in ten UK director-dealing announcements are currently refused: prose press releases with no template, several directors in one notice, ADR-denominated deals, and figures the filing's own aggregate doesn't confirm. Each is refused rather than guessed. The coverage page marks the UK as partial for that reason, and the share goes up as each format gets its own parser.

Getting started

Create an account and generate a key on the API key page. The free plan covers Sweden and Spain, so you can try the API there first; the UK is on the full plan (see pricing). The docs list every parameter, and coverage shows how far back each register goes. The UK starts in July 2016.