API Documentation

Everything you need to fetch your blog content via the Blotd API.

Getting Started

  1. Sign up - Create a free account at blotd.com/login
  2. Get your API key - Go to Dashboard > API Keys and copy your key
  3. Make your first request - See the example below

Authentication

All API requests require a Bearer token in the Authorization header:

Header
Authorization: Bearer blotd_xxxxxxxxxxxx

Keep your API key safe

Never expose your API key in client-side code, public repositories, or browser requests. Store it as an environment variable (e.g. BLOTD_API_KEY) and only use it in server-side code such as API routes, server components, or build scripts. If you believe a key has been compromised, revoke it immediately from your dashboard and create a new one.

Base URL

https://api.blotd.com/v1

Endpoints

GET/articles

List all published articles, paginated.

Query Parameters

ParamTypeDefaultDescription
pagenumber1Page number
limitnumber10Items per page (max 50)
sortstringnewestnewest or oldest
tagstring-Filter by tag

Example

const res = await fetch(
  "https://api.blotd.com/v1/articles?page=1&limit=10",
  {
    headers: {
      Authorization: "Bearer blotd_xxxxxxxxxxxx",
    },
  }
);
const { data, pagination } = await res.json();
GET/articles/:slug

Get a single article by its slug.

const res = await fetch(
  "https://api.blotd.com/v1/articles/my-first-post",
  {
    headers: {
      Authorization: "Bearer blotd_xxxxxxxxxxxx",
    },
  }
);
const { data } = await res.json();
GET/articles/tag/:tag

Filter articles by tag. Supports the same pagination params as /articles.

GET/articles/search?q=query

Search articles by title, content, or tags.

Response Format

All responses follow this shape:

{
  "success": true,
  "data": { ... },
  "pagination": {
    "page": 1,
    "limit": 10,
    "total": 42,
    "totalPages": 5
  }
}

Rate Limits

PlanMonthly LimitExceeded
Free1,000 requests429 Too Many Requests
Pro25,000 requests429 Too Many Requests

Code Examples

Next.js (App Router)

app/blog/page.tsx
async function getArticles() {
  const res = await fetch(
    "https://api.blotd.com/v1/articles",
    {
      headers: {
        Authorization: `Bearer ${process.env.BLOTD_API_KEY}`,
      },
      next: { revalidate: 60 },
    }
  );
  return res.json();
}

export default async function BlogPage() {
  const { data } = await getArticles();

  return (
    <div>
      {data.map((post) => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.readingTime}</p>
          <div dangerouslySetInnerHTML={{ __html: post.content }} />
        </article>
      ))}
    </div>
  );
}

Astro

src/pages/blog.astro
---
const res = await fetch(
  "https://api.blotd.com/v1/articles",
  {
    headers: {
      Authorization: `Bearer ${import.meta.env.BLOTD_API_KEY}`,
    },
  }
);
const { data: posts } = await res.json();
---

{posts.map((post) => (
  <article>
    <h2>{post.title}</h2>
    <Fragment set:html={post.content} />
  </article>
))}

Plain JavaScript

fetch("https://api.blotd.com/v1/articles", {
  headers: {
    Authorization: "Bearer blotd_xxxxxxxxxxxx",
  },
})
  .then((res) => res.json())
  .then(({ data }) => {
    data.forEach((post) => {
      console.log(post.title, post.slug);
    });
  });

Best Practices

Cache responses server-side

Blog content changes infrequently. Cache API responses so one request serves thousands of visitors. In Next.js, use revalidate for time-based caching:

await fetch(url, { next: { revalidate: 60 } })

Use on-demand revalidation for zero waste

Even better than time-based caching: tag your fetches and only invalidate when content actually changes. Your pages stay fully cached until you publish, update, or delete an article.

// In your page (cache indefinitely)
await fetch(url, { next: { tags: ["blog"] } })

// In your publish/update handler (bust the cache)
import { revalidateTag } from "next/cache"
revalidateTag("blog")

Fetch only what you need

Use ?limit=5 if your homepage only shows 5 posts. Filter by tag with ?tag=tutorials for specific sections. Smaller responses mean faster loads and fewer wasted API calls.

Handle errors gracefully

Always handle 401, 404, and 429 responses. Show fallback UI when the API is unreachable, a friendly message for missing articles, and a retry prompt when rate-limited. Never let an API error crash your page.

Error Codes

CodeMeaning
200Success
400Bad request (missing params)
401Unauthorized (missing or invalid API key)
404Article not found
429Rate limit exceeded
500Server error