Blog API
Publish a post to the Fareletter blog with a single HTTP request, authenticated with a shared key (ask the site owner for one). Posts are not otherwise reviewed before going live. Submitted Markdown is still sanitized server-side (scripts, event handlers and dangerous links are stripped), so a mistaken or leaked-key post still can't attack other visitors.
Publish a post
POST https://fareletter.com/api/postsContent-Type: application/jsonAuthorization: Bearer <your key>
| Field | Required | Notes |
|---|---|---|
| title | yes | 3-120 characters |
| markdown | yes | 80-50,000 characters. Standard Markdown (GFM): headings (## and below), lists, links, images, blockquotes, code, tables. Raw HTML is stripped, not rejected - don't rely on embedding HTML |
| excerpt | no | Up to 300 characters; auto-derived from the post body if omitted |
| cover | no | A valid http(s) image URL, used as the card/social-share image. Images in the body are referenced by URL the same way - there is no upload endpoint |
| author | no | Up to 80 characters; defaults to "Fareletter community" |
| tags | no | Up to 8 strings, 24 characters each |
Request example
{
"title": "My trip to Bangkok on a budget",
"markdown": "## Why Bangkok\n\nBangkok is one of the cheapest long-haul-feeling trips from India...\n\n\n\n- Flights: look for AirAsia or IndiGo sales\n- Stay: Sukhumvit for easy transit\n\n> Book the non-stop if the price gap is under ₹2,000 - the connection risk isn't worth it for less.\n",
"excerpt": "A short, practical guide to a budget Bangkok trip from India.",
"cover": "https://example.com/cover.jpg",
"author": "A reader",
"tags": ["bangkok", "budget"]
}Success response - 201 Created
{
"ok": true,
"slug": "my-trip-to-bangkok-on-a-budget",
"url": "https://fareletter.com/blog/my-trip-to-bangkok-on-a-budget",
"title": "My trip to Bangkok on a budget",
"excerpt": "A short, practical guide to a budget Bangkok trip from India.",
"date": "2026-10-24",
"mins": 2
}Errors
| Status | error | When |
|---|---|---|
| 400 | validation | A field fails the rules above - the response includes a fields object naming each problem |
| 400 | invalid_json | Body isn't valid JSON |
| 401 | unauthorized | Missing or wrong Authorization: Bearer key |
| 409 | slug_exhausted | Extremely unlikely - too many posts already share the derived slug |
| 413 | payload_too_large | Request body over ~80,000 bytes |
| 415 | unsupported_media_type | Content-Type isn't application/json |
| 429 | rate_limited | More than 3 posts from the same IP in an hour |
List posts
GET https://fareletter.com/api/posts returns the most recent posts as JSON:
{ "posts": [ { "slug": "...", "title": "...", "excerpt": "...", "cover": "...", "author": "...", "tags": [], "date": "2026-10-24", "mins": 2, "url": "..." } ] }curl example
curl -X POST https://fareletter.com/api/posts \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_KEY" \
-d '{"title":"My trip to Bangkok","markdown":"## Why Bangkok\n\nSome text about the trip...\n\n"}'Limits
- 3 published posts per IP address per hour
- Markdown body: 80-50,000 characters
- Total request body: ~80,000 bytes
- No file uploads - images are referenced by URL only