Dailycal APIdailycal.org ↗
Browse and retrieve Daily Californian articles site-wide or by section. List articles newest-first and fetch full plain-text body content by article ID.
What is the Dailycal API?
The Daily Californian API exposes 2 endpoints that cover published articles from dailycal.org, UC Berkeley's independent student newspaper. Use list_articles to page through articles newest-first across the entire site or filtered to a specific section like opinion/editorials, and use get_article_text to retrieve the full body text, headline, byline, paragraph array, word count, and publish timestamp for any individual article by its UUID.
curl -X GET 'https://api.parse.bot/scraper/be1089d4-6f4f-4709-8684-cd734697f840/list_articles?section=opinion%2Feditorials' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace dailycal-org-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""Walkthrough: Daily Californian articles — browse editorials, read full text."""
from parse_apis.dailycal_org_api import DailyCal, ArticleNotFound
client = DailyCal()
# List recent editorials, capped at 5 total items.
for article_summary in client.article_summaries.list(section="opinion/editorials", limit=5):
print(article_summary.title, article_summary.published_at)
# Drill into the first result's full text via summary -> detail navigation.
lead = client.article_summaries.list(section="opinion/editorials", limit=1).first()
if lead is not None:
full = lead.details()
print(full.title, full.word_count, "words")
for paragraph in full.paragraphs[:3]:
print(paragraph[:120])
# Point-lookup by id discovered from a previous listing.
if lead is not None:
try:
article = client.articles.get(article_id=lead.article_id)
print(article.title, "|", article.author)
except ArticleNotFound:
print("article removed since listing")
print("exercised: article_summaries.list / details / articles.get")
Lists published articles sorted by publish time, newest first. One round trip per call. Without a section it covers the whole site; with a section slug path (as it appears in article URLs, e.g. opinion/editorials) it covers only that section and its descendants. Paginates by offset: `offset` (default 0) and `limit` (default 25, clamped to 100); the response carries the source's `total`, `has_more`, and `next_offset` (null when the result space is exhausted). An unknown section returns an empty `articles` array with total 0. Each item's `article_id` feeds get_article_text.
| Param | Type | Description |
|---|---|---|
| limit | integer | Number of articles to return per page; values above 100 are clamped to 100. |
| offset | integer | Zero-based position in the newest-first result space to start from; pass the previous response's next_offset to continue. |
| section | string | Section slug path exactly as it appears in article URLs (lowercase, slash-separated), e.g. opinion/editorials or news. Omitted = all articles site-wide. |
{
"type": "object",
"fields": {
"limit": "integer page size that was applied after clamping",
"total": "integer total number of matching articles reported by the site",
"offset": "integer offset that was applied",
"section": "section filter that was applied, or null for site-wide",
"articles": "array of article summaries, newest first: article_id (UUID for get_article_text), title, subheadline, url, published_at (ISO 8601 with offset), updated_at, sections (slug paths), keywords, authors (byline strings), summary (plain-text lede), thumbnail_url",
"has_more": "boolean, true when further pages exist",
"next_offset": "integer offset for the next page, or null when no more results"
},
"sample": {
"data": {
"limit": 5,
"total": 71,
"offset": 0,
"section": "opinion/editorials",
"articles": [
{
"url": "https://www.dailycal.org/opinion/editorials/in-the-age-of-ai-generated-public-messages-human-imperfection-is-worth-defending/article_1021b4f2-7ecf-4d6c-9aa8-a7195048e7b6.html",
"title": "In the age of AI-generated public messages, human imperfection is worth defending",
"authors": [
"Editorial Board"
],
"summary": "As tools designed to choose the statistically most appropriate language in a given setting, the frequent and unchecked use of LLMs serves to flatten language across fields.",
"keywords": [
"pangram",
"uc berkeley",
"ai"
],
"sections": [
"opinion/editorials"
],
"article_id": "1021b4f2-7ecf-4d6c-9aa8-a7195048e7b6",
"updated_at": null,
"subheadline": null,
"published_at": "2026-09-03T07:00:00-07:00",
"thumbnail_url": "https://bloximages.chicago2.vip.townnews.com/dailycal.org/content/tncms/assets/v3/editorial/c/fd/cfd5f0db-9b6a-4bcd-a2bd-80cc85d58648/6a99a3e67305a.image.jpg?resize=640%2C412"
}
],
"has_more": true,
"next_offset": 5
},
"status": "success"
}
}About the Dailycal API
Listing Articles
The list_articles endpoint returns a newest-first array of article summaries from dailycal.org. Each object in the articles array includes an article_id (UUID), title, subheadline, url, and published_at in ISO 8601 format. Without a section parameter the query covers the entire site; passing a section slug such as opinion/editorials or news restricts results to that section and its descendants, matching the path structure as it appears in article URLs. Page size is controlled with limit (capped at 100) and offset for cursor-style pagination. The response includes total, has_more, and next_offset so you can walk through the full result set.
Fetching Article Text
The get_article_text endpoint takes a single required parameter, article_id, which must be a UUID exactly as returned by list_articles. It returns the full article body as both a paragraphs array (one element per body paragraph, plain text, in reading order) and a single text string with paragraphs joined by blank lines. Supporting fields include title, author (byline as published, which may carry a role suffix like | Staff), published_at, canonical URL, and an integer word_count.
Coverage and Scope
Content spans all sections published on dailycal.org, including news, opinion, editorials, sports, arts, and more. Section filtering uses the slug path exactly as it appears in URLs — for example, opinion/editorials — so multi-level section hierarchies are supported. The total field in list responses reflects the site's reported count of matching articles, not a local cache, so it tracks publication activity accurately.
The Dailycal API is a managed, monitored endpoint for dailycal.org — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when dailycal.org changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official dailycal.org API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Monitor the
opinion/editorialssection for new UC Berkeley editorial positions usinglist_articleswith thesectionfilter - Build a campus news digest by paginating
list_articlessite-wide and storingtitle,subheadline, andurlfields - Extract full article text via
get_article_textfor NLP analysis or sentiment classification of student journalism - Track byline frequency using the
authorfield returned byget_article_textto identify prolific student contributors - Compute reading time estimates by using the
word_countfield fromget_article_textacross a batch of articles - Detect publication volume trends over time by collecting
published_attimestamps fromlist_articlesacross sections
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 200 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
| Team | $300/mo | 20,000 | 300 req/min |
| Company | $1,000/mo | 100,000 | 500 req/min |
Each endpoint has a fixed posted price per successful call — most fall between 1 and 10 credits — shown on this API's page before you run it. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does the Daily Californian have an official developer API?+
How does section filtering work in `list_articles`?+
section parameter as the slug path exactly as it appears in article URLs — lowercase and slash-separated, for example opinion/editorials or sports. The filter covers the specified section and its descendants. Without a section parameter, the endpoint returns articles from across the entire site, newest first.What does pagination look like for `list_articles`?+
has_more (boolean), next_offset (integer or null), total (total matching articles), offset (applied offset), and limit (applied page size). Pass next_offset from one response as offset in the next call to walk through results. The maximum page size is 100; values above that are clamped automatically.Does the API return article comments, tags, or author profile data?+
list_articles and body text, byline, and word count from get_article_text. Comments, topic tags, and author profile pages are not included in either endpoint's response. You can fork this API on Parse and revise it to add an endpoint covering those fields.Is there a way to search articles by keyword rather than browsing by section?+
section and paginating newest-first but does not offer free-text keyword search. You can fork this API on Parse and revise it to add a search endpoint.