---
name: ofac-sanctions-list-service-ingestion
description: "How to get OFAC Sanctions List Service data into a pandas DataFrame and Parquet: access, the request, the format, limits, quirks and terms."
---

# Load the OFAC SDN list into pandas and Parquet

Source entry: https://signal-lab-jet.vercel.app/datasets/ofac-sanctions-list-service
Provider: https://ofac.treasury.gov/sanctions-list-service
Checked against the provider's documentation: 2026-11-02

## Access
- No account or key. Files download over HTTPS from OFAC's Sanctions List Service.
- The SDN and consolidated non-SDN lists come in XML and CSV; the XML starts with a Publish_Date and Record_Count header.

## Request
```bash
curl -L -o SDN.XML 'https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/SDN.XML'
```

## Format
XML sdnList with publshInformation (Publish_Date, Record_Count) and one sdnEntry per record: uid, lastName, firstName, sdnType (Individual, Entity, Vessel or Aircraft), programList, akaList, addressList, idList and, for vessels, vesselInfo.

## Load into pandas and Parquet
Needs Python 3 with requests, pandas and pyarrow.
```python
"""OFAC SDN list (XML) -> pandas -> Parquet. No key."""
import xml.etree.ElementTree as ET
import requests
import pandas as pd

URL = "https://sanctionslistservice.ofac.treas.gov/api/PublicationPreview/exports/SDN.XML"
r = requests.get(URL, timeout=180)
r.raise_for_status()
root = ET.fromstring(r.content)
ns = {"s": root.tag.split("}")[0].strip("{")}
info = root.find("s:publshInformation", ns)
rows = []
for e in root.findall("s:sdnEntry", ns):
    rows.append({
        "uid": int(e.findtext("s:uid", namespaces=ns)),
        "last_name": e.findtext("s:lastName", default="", namespaces=ns),
        "first_name": e.findtext("s:firstName", default="", namespaces=ns),
        "sdn_type": e.findtext("s:sdnType", default="", namespaces=ns),
        "programs": ";".join(p.text for p in e.findall("s:programList/s:program", ns)),
        "aka_count": len(e.findall("s:akaList/s:aka", ns)),
    })
df = pd.DataFrame(rows)
df["publish_date"] = pd.to_datetime(info.findtext("s:Publish_Date", namespaces=ns), format="%m/%d/%Y")
df.to_parquet("ofac_sdn.parquet", index=False)
print(len(df), "SDN entries; published", df["publish_date"].iloc[0].date(),
      "; types:", df["sdn_type"].value_counts().to_dict())
```
Run by us on 2026-11-02 (python 3.13.5 | pandas 3.1.0 | pyarrow 26.0.0 | requests 2.34.2). Result: 19484 SDN entries; published 2026-10-28 ; types: {'Entity': 10045, 'Individual': 7529, 'Vessel': 1568, 'Aircraft': 342}

## Limits
- Rate limits: Not stated.
- Files are large (the SDN XML was about 29 MB on 2026-11-02), so download on a schedule rather than per lookup.

## Quirks
- SDN.CSV has no header row; the XML carries named fields.
- OFAC keeps only the active lists, not archived versions, so keep your own dated copies if you need point-in-time history.
- Individuals, entities, vessels and aircraft share one list; sdnType tells them apart.

## Terms and attribution
- The checked OFAC pages state no separate data licence or reuse terms.
- Terms page: https://ofac.treasury.gov/sanctions-list-service

## Sources
- https://ofac.treasury.gov/sanctions-list-service: "the SDN list contains the names of individuals, entities and groups designated by OFAC as well as the listing of maritime vessels and aircraft that are blocked by OFAC."
- https://ofac.treasury.gov/faqs/topic/1641: "OFAC's SDN list is available in XML, fixed-field and delimited formats that can be imported into a variety of software programs."
- https://ofac.treasury.gov/faqs/topic/1641: "changes to the sanctions lists can be sporadic"
- https://ofac.treasury.gov/specially-designated-nationals-list-sdn-list/archive-of-changes-to-the-sdn-list: "records are maintained here back to 1994"

## Help improve this skill
Missing a source, or see something to improve? Call the MCP tool suggest_source or feedback (or POST /api/suggest or /api/feedback). Reviewed ideas: https://signal-lab-jet.vercel.app/agent-suggestions

Information for educational purposes only. Free tiers, limits and licenses belong to the providers and may change; check the provider's own terms before using the data.
