MailerDot Developer Documentation
The MailerDot API, MCP server, and agent-readable resources — every U.S. city we publish, its daily editions, weather, and census facts. Read-only, no key, no sign-up, CORS open.
Base URL: https://mailerdot.com · OpenAPI 3.1 spec · MCP server · This page as markdown
Authentication
None. Every endpoint below is public and read-only — one exception, POST /api/subscribe — and needs no key, token, account, or sign-up. There is no sandbox because there is nothing to break: the read endpoints cannot mutate anything, so you can develop against production directly.
Quickstart
# 1. Find a city
curl -s 'https://mailerdot.com/api/cities'
# 2. Read its latest edition as markdown
curl -s 'https://mailerdot.com/austin-texas.md'
# 3. Search every archive
curl -s 'https://mailerdot.com/api/search?q=farmers+market&limit=3'City slugs
Every endpoint is keyed by a slug of the form `{city}-{state-name}`, lowercased and hyphenated — `austin-texas`, `san-francisco-california`, `new-york-new-york`. The state is the full name, not the postal abbreviation. Fetch https://mailerdot.com/api/cities for the authoritative list.
API endpoints
| Method | Path | Returns |
|---|---|---|
GET | /api/cities | Every city with a published edition, grouped by state. |
GET | /api/cities-census | Census-tracked cities, filterable by population and state. |
GET | /api/city/{slug} | One city: subscriber count, archive index, census snapshot, events, directory. |
GET | /api/archive/{slug}/{date} | One past edition. Append `.md` to the date for markdown instead of JSON. |
GET | /api/search | Full-text search across every archived edition, with highlighted snippets. |
GET | /api/weather/{slug} | Today's forecast — the stored snapshot the edition used, or a live fetch. |
GET | /api/facts/{slug} | Schema.org Dataset facts for a city: newsletter metadata plus ACS demographics. |
GET | /api/territories | Whether a town can be leased and what it costs. No query returns the taken list. |
GET | /api/oembed | oEmbed provider for city and edition pages (rich iframe embeds). |
POST | /api/subscribe | Subscribe an address to a city. The only open write endpoint. |
Full parameters and response schemas: https://mailerdot.com/openapi.json
Error responses
Every failure answers with application/problem+json (RFC 9457) — never an HTML page, on any path under /api/, including ones that do not exist. Branch on code; it is stable. resolution says what to do next, and issues[] lists per-field failures on a validation error.
| Code | HTTP | Meaning | What to do |
|---|---|---|---|
city_not_found | 404 | No MailerDot city for that slug | Fetch https://mailerdot.com/api/cities for every city with a published edition. A U.S. city with no MailerDot edition yet has no data to return; subscribing to it creates one. |
conflict | 409 | Request conflicts with current state | Re-read the resource to see its current state, then decide whether to retry. |
edition_not_found | 404 | No edition published for that date | Fetch https://mailerdot.com/api/city/{slug} for the dates that exist. Editions publish each morning in the city's own timezone, so today's may not exist yet. |
endpoint_not_found | 404 | No such API endpoint | Every public endpoint is listed in https://mailerdot.com/openapi.json and https://mailerdot.com/.well-known/api-catalog. Human-readable docs: https://mailerdot.com/developers. |
forbidden | 403 | Not permitted | The credential is valid but does not grant this action. Nothing to retry. |
internal_error | 500 | Unexpected server error | Retry once; this is usually transient. If it persists, report it at https://mailerdot.com/contact with the request path and time. |
invalid_json | 400 | Request body is not valid JSON | Send a JSON body with `Content-Type: application/json`, then retry. |
invalid_slug | 400 | City slug is not well-formed | Slugs are `{city}-{state-name}`, lowercased and hyphenated — `austin-texas`, `san-francisco-california`. List valid slugs at https://mailerdot.com/api/cities. |
method_not_allowed | 405 | HTTP method not allowed | Use one of the methods in the `Allow` response header. Per-endpoint methods are in https://mailerdot.com/openapi.json. |
missing_slug | 400 | City slug is missing | Put a city slug in the path, e.g. `/api/city/austin-texas`. List valid slugs at https://mailerdot.com/api/cities. |
not_found | 404 | Resource not found | Check the identifier and retry. The available endpoints are listed at https://mailerdot.com/openapi.json. |
payload_too_large | 413 | Request body is too large | Send a smaller body. The per-endpoint limit is in the `detail` field. |
rate_limited | 429 | Rate limit exceeded | Back off and retry after the `Retry-After` header's number of seconds. |
service_misconfigured | 503 | Service is misconfigured | The deployment is missing required configuration and cannot serve the API. This is our problem, not the caller's — retry later or report it at https://mailerdot.com/contact. |
unauthorized | 401 | Authentication required | This endpoint is not part of the public API. Sign in at https://mailerdot.com/operators — the public, unauthenticated surface is documented at https://mailerdot.com/developers. |
upstream_error | 502 | An upstream service failed | A third-party dependency failed or timed out. Retry with backoff. |
validation_error | 400 | Request validation failed | Read `issues[]` for the per-field failures, fix the request, and retry. Request shapes are documented at https://mailerdot.com/openapi.json. |
weather_unavailable | 404 | No weather available for that city | The city resolved but neither a stored snapshot nor a live forecast was available. Retry later; weather is refreshed with each morning's edition. |
Markdown for agents
Every page has a markdown twin. Append .md to the path, or send Accept: text/markdown. Responses carry an X-Markdown-Tokens header with a rough token estimate.
https://mailerdot.com/{slug}.md— A city page: latest edition, archive index, census table.https://mailerdot.com/{slug}/{YYYY-MM-DD}.md— One dated edition, in full.https://mailerdot.com/cities.md— The whole city directory.https://mailerdot.com/states/{state}.md— Every tracked city in one state, by population.https://mailerdot.com/feed.md— The 30 most recent editions across all cities.https://mailerdot.com/developers.md— This page.
MCP server
https://mailerdot.com/mcp speaks the Model Context Protocol over streamable HTTP, unauthenticated. Point any MCP client at it:
{
"mcpServers": {
"mailerdot": {
"url": "https://mailerdot.com/mcp"
}
}
}Tools:
list_cities— Every city with an active newsletter, grouped by state.get_city— City overview: subscribers, census demographics, recent editions.get_archive— Read a past edition as markdown.search_archives— Full-text search across every edition.get_weather— Today's weather for a city.
It also serves resources/list, resources/templates/list, resources/read, and prompts/list.
Machine-readable discovery
- OpenAPI 3.1 specification
application/json— The full contract: every endpoint, schema, and error code. Generate a client from it. - MCP server
application/json— Model Context Protocol over streamable HTTP. Tools, resources, and prompts. - API catalog (RFC 9727)
application/linkset+json— Linkset pointing at everything on this list. The standard discovery entry point. - Agent Skills index
application/json— A SKILL.md an agent can load to learn the URL shapes without crawling for them. - llms.txt
text/plain— What MailerDot is, in one page, written for a language model. - llms-full.txt
text/plain— The long form: product, editorial policy, operator terms, and API notes. - RSS feed
application/rss+xml— The most recent editions across every city. - Sitemap index
application/xml— Every indexable URL: cities, states, and dated editions.
Limits and conventions
- No API key, no account, no rate limit on the read endpoints. Be reasonable and cache what you fetch — responses carry real `Cache-Control` headers, so honouring them costs you nothing.
- Every read endpoint sends `Access-Control-Allow-Origin: *`, so browser-side agents can call them directly.
- Markdown responses carry an `X-Markdown-Tokens` header with a rough token estimate, so you can decide whether to fetch a full edition or stop at the summary.
- Editions publish each morning in the city's own timezone. Asking for today's edition before it publishes returns a 404 with the `edition_not_found` code, not the previous day's content.
- Coverage is the United States only.
Support
- Questions and bug reports: https://mailerdot.com/contact — we reply within 3 business days
- Security reports: security.txt
- Terms · Privacy