Data API
Everything in the Policy Atlas is available as JSON through a free, read-only API. No key or sign-up is needed, and it can be called from scripts, notebooks or other websites.
It serves exactly what the Atlas pages show, from the same code: records held back for review stay held back here too, and nothing private is included. For everything at once, the bulk downloads are quicker.
Before you use it
- Automated readings are unchecked. Fields under
automated_readingcome from NSMPA's automated reading of each website. Nobody has checked them by hand; they are leads, not our findings. - "Not located" isn't "none". If the search didn't locate a policy, the newsroom may still have one.
- The counts aren't national figures. They describe only the newsrooms we've listed.
- Skip the examples. Records with
is_example: trueare made up to show the format. - Cite the date. Data changes as records are checked; cite the time you retrieved it (see Citing).
Search and filter records
GET https://archiveethics.org/api/v1/records
Returns records in a compact form, 50 at a time, with the same filters as the Atlas. Every parameter is optional.
| Parameter | What it does | Values |
|---|---|---|
q | Search text: matches the name, parent institution (college or company), city, a website address, or a full state name. Closest name matches come first. | — |
state | Two-letter state code, e.g. TX. | — |
type | Publication type. | student_media, professional, journalism_organization |
medium | Only TV and radio newsrooms. | broadcast |
policy | Whether the automated search found a policy page (unchecked). not_located never means the newsroom has no policy. | found, not_located, unreadable |
finding | The automated reading in full (unchecked). | NO_RELEVANT_GUIDANCE, UNDETERMINED, SUPPORTS_CHANGED_CIRCUMSTANCES, SUPPORTS_RELIEF, CASE_BY_CASE, UPDATE_ONLY, STRICT_ARCHIVE, MIXED |
pt | Policy transparency code of a published classification. | PT1, PT2, PT3, PT4, PT5, PT6 |
remedy | With position: records whose published classification takes that position on that remedy. | correction, contextual_update, editors_note, anonymization, deindexing, removal |
position | Used with remedy. | expressly_permitted, case_by_case, expressly_prohibited, not_established |
sort | Order of results (default name). | name, type, pt, verified |
dir | asc (default) or desc. | asc, desc |
limit | Records per page, 1–500 (default 50). | — |
offset | How many records to skip (default 0). Or follow meta.next. | — |
Try it:
- Student newspapers in Texas:
/api/v1/records?state=TX&type=student_media - Where the automated search found a policy page:
/api/v1/records?policy=found&limit=100 - Search by place:
/api/v1/records?q=Boston - Look up a website:
/api/v1/records?q=dailytrib.com - One record in full:
/api/v1/records/komu-tv
A response looks like this (a made-up example record):
{
"meta": {
"total": 1,
"count": 1,
"limit": 50,
"offset": 0,
"next": null,
"filters": { "q": "example", "sort": "name", "dir": "asc" },
"data_last_updated": "2026-10-14T18:20:00.000Z",
"generated_at": "2026-10-14T21:00:00.000Z",
"license": "CC BY 4.0 …",
"notice": "Live snapshot … not a versioned dataset release …"
},
"records": [
{
"institution_id": "aep-example-001",
"slug": "example-student-news",
"publication": "Example Student News",
"is_example": true,
"parent_institution": "Example University",
"publication_type": "student_media",
"medium": null,
"state": "TX",
"city": null,
"website": "https://example.org",
"profile_url": "https://archiveethics.org/atlas/example-student-news",
"api_url": "https://archiveethics.org/api/v1/records/example-student-news",
"classification": {
"status": "published",
"policy_transparency": { "code": "PT1", "label": "Public written policy verified" },
"review_status": "preliminary",
"verified_date": "2026-10-11"
},
"automated_reading": null,
"outreach_status": "not_contacted",
"last_updated": "2026-10-11T00:00:00.000Z"
}
]
}classification.status is published, not_classified, under_review or suspended. Every field and code is explained in the codebook and the glossary.
One record in full
GET https://archiveethics.org/api/v1/records/{slug}
The slug is the last part of the record's address on the site (/atlas/{slug}), and each record in the list gives its api_url. The full record has the classification and position on each remedy, the sources, the policy pages with the dates they were first seen, the newsroom's own statements and the record's history. It's the same as the record's JSON download.
Example
# Every student newspaper in Texas, as JSON
curl 'https://archiveethics.org/api/v1/records?state=TX&type=student_media'
# In Python: all records, following the pages
import requests
url = 'https://archiveethics.org/api/v1/records?limit=500'
records = []
while url:
page = requests.get(url, timeout=30).json()
records += page['records']
url = page['meta']['next']Limits and errors
- Up to 120 requests a minute from one address. Over that, the API answers
429with aRetry-Afterheader. - A parameter or value it doesn't recognize gets
400with a message saying what's wrong, rather than a quiet, unfiltered result. - An unknown record is
404. Errors look like{ "error": { "status": 404, "message": "…" } }. - Responses may be cached for up to five minutes.
Stability
Within v1, fields won't be renamed or removed, and codes keep their meaning. New fields may be added, so ignore any you don't recognize. A change that would break existing code would come as v2, with v1 kept running alongside it.
Bulk files
For the whole Atlas at once: atlas.json, atlas.csv and evidence.csv. They take the same filters as the API, for example /data/atlas.csv?state=TX. More on the Data page.
Citing and reuse
The data is licensed CC BY 4.0: reuse it for any purpose, crediting the Archive Ethics Project with a link. Short quotes from newsrooms remain their work. Cite a retrieval like this:
The Archive Ethics Project. National Policy Atlas [data API, v1]. Retrieved [date], from https://archiveethics.org/api/v1/records.
Something wrong or missing? Tell us.