Overview
This API returns the same public post feed style used in Genjutsu, including likes, comments, views, media, code, and readme-format metadata.
- Public-only feed data
- 24-hour retention window
- Pagination via
pageandlimit - Live polling support via
since
Beginner Setup (Step by Step)
- Choose your base URL:
https://genjutsu.xyz - Build the endpoint URL:
/api/genjutsu-feed?page=1&limit=10 - Send a
GETrequest using browser fetch, backend code, or cURL. - Check
ok === truebefore readingposts. - Render each post card using
content,media_url, counts, andprofile. - For live updates, save
meta.server_timeand send it back assince. It is bucketed for shared cache efficiency.
If your site is static HTML/CSS/JS, you can use fetch directly in the browser. If your site is server-rendered, call this API on your backend and render from there.
Query Parameters
| Param | Type | Default | Description |
|---|---|---|---|
page |
number | 1 | Page number (1-based). |
limit |
number | 10 | Posts per page (max 50). |
since |
ISO string | null | Only include posts newer than this timestamp (still constrained to 24h). |
Validation rules:
pagemust be a positive integer.limitmust be a positive integer and is capped at50.sincemust be a valid ISO timestamp like2026-04-28T10:30:00.000Z.- For best cache reuse, pass back
meta.server_timeinstead of generating your own fresh timestamp.
Response Shape
{
"ok": true,
"meta": {
"page": 1,
"limit": 10,
"has_more": true,
"since": null,
"window_hours": 24,
"server_time": "2026-04-28T10:35:00.000Z",
"poll_bucket_seconds": 60
},
"posts": [
{
"id": "uuid",
"content": "post text",
"code": "const x = 1;",
"code_language": "javascript",
"media_url": "https://...",
"tags": ["react", "supabase"],
"created_at": "2026-04-28T09:00:00.000Z",
"edited_at": null,
"user_id": "uuid",
"is_readme": false,
"views_count": 13,
"likes_count": 5,
"comments_count": 2,
"profile": {
"username": "ovi",
"display_name": "Ovi",
"avatar_url": "https://..."
}
}
]
}
Post Field Guide
| Field | Type | How To Use |
|---|---|---|
id |
string | Unique key for rendering list items. |
content |
string | null | Main post text. |
code |
string | null | Code snippet body (if post contains code). |
code_language |
string | null | Syntax language label for code highlighting. |
media_url |
string | null | Image/media URL. Show only when present. |
tags |
string[] | Topic chips/labels. |
created_at |
ISO string | Post publish time. |
edited_at |
ISO string | null | Edit timestamp if post was updated. |
is_readme |
boolean | If true, render in README-style post layout. |
views_count |
number | Total views count. |
likes_count |
number | Total likes count. |
comments_count |
number | Total comments count. |
profile.username |
string | null | Author handle. |
profile.display_name |
string | null | Author display name. |
profile.avatar_url |
string | null | Author avatar image URL. |
Errors & Status Codes
| Status | When | Example |
|---|---|---|
200 |
Successful request. | { "ok": true, ... } |
400 |
Invalid query parameter (for example invalid since format). |
{ "ok": false, "error": "Invalid `since` parameter..." } |
405 |
Method not allowed (only GET / OPTIONS allowed). |
{ "ok": false, "error": "Method Not Allowed" } |
500 |
Unexpected internal server error. | { "ok": false, "error": "Unexpected server error" } |
502 |
Upstream data fetch issue while building feed or counts. | { "ok": false, "error": "Failed to fetch posts" } |
All error responses follow a JSON shape with ok: false and an error message.
Caching Behavior
The public API is tuned for shared edge caching. Common feed pages can stay cached a bit longer, while since-based refreshes use shorter cache windows.
- Reuse
meta.server_timeas your nextsincevalue. - Avoid generating a brand new timestamp on every poll.
- Use small limits for live refreshes whenever possible.
Rate Limits & Fair Use
There is no dedicated API key or public per-user quota yet, but consumers should use reasonable polling and caching behavior.
- Recommended polling interval for live updates: every 60 seconds (matching the server bucket).
- Avoid high-frequency loops (for example sub-second polling).
- Use
sinceto fetch only new posts instead of repeatedly requesting large pages. - Respect caching headers returned by the endpoint when possible.
Future versions may enforce hard rate limits and API key-based access controls.
Quick Start
const res = await fetch("https://genjutsu.xyz/api/genjutsu-feed?limit=10&page=1");
const data = await res.json();
console.log(data.posts);
cURL Example
curl "https://genjutsu.xyz/api/genjutsu-feed?page=1&limit=10"
Frontend Example (Render Cards)
<div id="feed"></div>
<script>
async function loadFeed() {
const res = await fetch("https://genjutsu.xyz/api/genjutsu-feed?page=1&limit=10");
const data = await res.json();
if (!data.ok) return;
const root = document.getElementById("feed");
root.innerHTML = data.posts.map((post) => `
<article>
<h3>@${post.profile?.username || "unknown"}</h3>
<p>${post.content || ""}</p>
${post.media_url ? `<img src="${post.media_url}" alt="post media" />` : ""}
<small>❤ ${post.likes_count} · 💬 ${post.comments_count} · 👁 ${post.views_count}</small>
</article>
`).join("");
}
loadFeed();
</script>
Live Feed Polling Example
let since = new Date().toISOString();
async function pollFeed() {
const url = new URL("https://genjutsu.xyz/api/genjutsu-feed");
url.searchParams.set("since", since);
url.searchParams.set("limit", "20");
const res = await fetch(url.toString());
const data = await res.json();
if (!data.ok) return;
// newest first from API: reverse if you append top-down
for (const post of data.posts.reverse()) {
console.log("new post", post.id, post.content);
}
since = data.meta.server_time;
}
setInterval(pollFeed, 10000);
Use since polling for efficient updates. It avoids re-fetching older posts each time.
Common Mistakes
- Passing invalid
sinceformat (must be ISO timestamp). - Requesting
limitover50and expecting more than the cap. - Assuming this endpoint returns data older than 24 hours.
- Not checking
okbefore readingposts. - Rendering
media_urlwithout null checks.
Deployment Checklist
- Deploy branch that includes
/api/genjutsu-feedand/api-docs. - Open docs via
http(s)URL, notfile://. - Test from mobile and desktop.
- Add caching/polling control on your client app.
- Gracefully handle non-200 responses.
Try It
Run a request to preview JSON response here.