API Reference
The RankFlo Content Delivery API lets you fetch published posts, search content, and embed analytics into any website or app. All endpoints are public, CORS-enabled, and require only a Project API Key.
Authentication
Every request needs your Project API Key (blg_xxx). Get yours from Dashboard → Projects.
# Query parameter (simplest — safe for frontend)
GET /api/v1/content?project_key=blg_xxx
# Authorization header
GET /api/v1/content
Authorization: Bearer blg_xxxProject keys only return published posts. Drafts and scheduled posts are never exposed.
Base URL
https://app.rankflo.ioFor self-hosted instances, replace with your own domain. All endpoints are at /api/v1/.
Rate Limits
120 requests per minute per project key (sliding window). Returns 429 Too Many Requests with Retry-After header when exceeded.
GET /api/v1/content
Fetch published posts for a project.
curl "https://app.rankflo.io/api/v1/content?project_key=blg_xxx"Query parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
project_key | string | — | Required. Your project API key |
slug | string | — | Fetch a single post by slug |
page | number | 1 | Page number |
limit | number | 20 | Posts per page (max 100) |
sort | string | newest | newest / oldest / title / updated |
tag | string | — | Filter by tag slug |
locale | string | — | Filter by locale (en, fr) |
format | string | html | html or json (raw blocks) |
fields | string | — | Sparse fieldset (title,slug,excerpt) |
updated_since | string | — | ISO 8601 timestamp for incremental sync |
Response
{
"data": [{
"id": "abc123",
"slug": "my-first-post",
"title": "My First Post",
"excerpt": "A short summary.",
"content": "<p>Full HTML content...</p>",
"featuredImage": "https://...",
"readingTime": 5,
"publishedAt": "2026-03-15T09:00:00.000Z",
"author": { "name": "Jane Smith" },
"tags": [{ "name": "SEO", "slug": "seo" }],
"seo": {
"metaTitle": "My First Post",
"metaDescription": "A short summary.",
"ogImage": "https://..."
}
}],
"meta": {
"page": 1,
"limit": 20,
"total": 47,
"totalPages": 3
}
}GET /api/v1/search
Full-text search across published posts using Postgres FTS.
curl "https://app.rankflo.io/api/v1/search?project_key=blg_xxx&q=headless+cms"| Parameter | Description |
|---|---|
q | Required. Search query |
limit | Max results (default 10, max 50) |
tag | Filter results by tag slug |
GET /api/v1/tags
List all tags for a project with post counts.
curl "https://app.rankflo.io/api/v1/tags?project_key=blg_xxx"Webhooks
RankFlo fires webhooks when posts are published or updated. See the Webhooks guide for payload format and signature verification.
Next.js Integration
// lib/rankflo.ts
const KEY = process.env.RANKFLO_PROJECT_KEY!;
const URL = "https://app.rankflo.io";
export async function getPosts(opts?: { tag?: string; limit?: number }) {
const params = new URLSearchParams({ project_key: KEY });
if (opts?.tag) params.set("tag", opts.tag);
if (opts?.limit) params.set("limit", String(opts.limit));
const res = await fetch(`${URL}/api/v1/content?${params}`, {
next: { revalidate: 60 },
});
return res.json();
}
export async function getPost(slug: string) {
const res = await fetch(
`${URL}/api/v1/content?project_key=${KEY}&slug=${slug}`,
{ next: { revalidate: 60 } }
);
const { data } = await res.json();
return data;
}// app/blog/page.tsx
import { getPosts } from "@/lib/rankflo";
export default async function BlogPage() {
const { data: posts } = await getPosts({ limit: 20 });
return (
<main>
{posts.map((post) => (
<article key={post.slug}>
<a href={`/blog/${post.slug}`}>{post.title}</a>
<p>{post.excerpt}</p>
</article>
))}
</main>
);
}Use revalidate: 60 for ISR — pages stay cached but refresh every 60 seconds. For instant updates, add a webhook that calls revalidatePath().