API · textlog

https://textlog.cc/apiskip to content
textlog
developers
Build on textlog
The public API is a small way to build feeds, profile cards, post embeds, and live widgets. Reading needs no account or API key, except personalized activity. Personalized activity and writing use a bearer token.
All API endpoints allow cross-origin requests. The machine-readable specification is at /api/openapi.json.
Endpoints
Base URL
https://textlog.cc/api/v1
POST/auth/request- Email a sign-in code to an existing account.
POST/auth/verify- Exchange the code for a session token.
DELETE/auth/session- Sign out by revoking the token you are using.
GET/me- Get the signed-in account.
PATCH/me- Update your bio.
POST/autotag- Enrich supplied text with relevant hashtags without saving a post.
POST/posts- Create a post, or reply by including
parent_id. GET/posts/:id- Get a single public post.
PATCH/posts/:id- Edit a post you own.
DELETE/posts/:id- Delete a post you own. Replies remain and the post becomes a “(deleted post)” tombstone.
POST/posts/:id/unpublish- Move a post you own back into your drafts.
GET/posts/:id/replies- Get replies recursively. Use the optional
depth query parameter (1–20, default 1). Each reply is returned with its depth, parent ID, and top_id; use its aggregate reply_count to detect omitted descendants. Top-level posts have a null top_id. POST/posts/:id/report- Report a post.
POST/posts/:id/bookmark- Bookmark a post. Repeating the request is safe.
DELETE/posts/:id/bookmark- Remove a post from your bookmarks.
POST/posts/:id/poll/votes- Vote in a poll. Results appear after voting or expiration.
GET/drafts- List your drafts.
POST/drafts- Create a post or reply draft.
GET/drafts/:id- Get one of your drafts.
PATCH/drafts/:id- Update one of your drafts.
DELETE/drafts/:id- Delete one of your drafts.
POST/drafts/:id/publish- Atomically publish and remove a draft.
GET/users/:handle- Get a public profile, relationship totals, and its pinned note and reply. Your authenticated profile also includes private blocked-user and blocked-tag counts.
GET/users/:handle/notes- Get a user's latest top-level notes.
GET/users/:handle/posts- Backward-compatible alias for
/users/:handle/notes. GET/users/:handle/replies- Get a user's latest replies.
GET/users/:handle/following/users- List accounts followed by a user.
GET/users/:handle/following/tags- List hashtags followed by a user.
GET/users/:handle/followers- List accounts following a user.
POST/users/:handle/follow- Follow a user.
DELETE/users/:handle/follow- Unfollow a user.
POST/users/:handle/block- Block a user.
DELETE/users/:handle/block- Unblock a user.
GET/users/:handle/blocks- List accounts you have blocked. The handle must be your own.
GET/feeds/all- Get all public posts and replies.
GET/feeds/all/conversations- Get the all feed grouped and classified like the web app.
POST/feeds/all/read- Mark selected all-feed posts as read using post_ids.
POST/feeds/all/read-all- Mark every visible all-feed post as read.
GET/feeds/hot- Get posts ranked by recent activity and replies.
GET/feeds/hot/conversations- Get the hot feed grouped and classified like the web app.
GET/activities/my-feed- Get activity from followed people and tags, plus activity directed to you.
GET/activities/my-feed/conversations- Get My Feed activity in web timeline order, with post activity grouped into conversations.
POST/activities/my-feed/read- Mark selected activities as read using their activity_ids.
POST/activities/my-feed/read-all- Mark every My Feed activity as read.
GET/activities/@- Get replies, mentions, and follows directed to you.
GET/activities/@/conversations- Get @ activity in web timeline order, with post activity grouped into conversations.
POST/activities/@/read- Mark selected @ activities as read using their activity_ids.
POST/activities/@/read-all- Mark every @ activity as read.
GET/tags/:tag- Get hashtag details and post and follower counts.
GET/tags/:tag/posts- Get the latest posts carrying a hashtag.
GET/tags/:tag/followers- List accounts following a hashtag.
POST/tags/:tag/follow- Follow a hashtag.
DELETE/tags/:tag/follow- Unfollow a hashtag.
POST/tags/:tag/block- Block a hashtag.
DELETE/tags/:tag/block- Unblock a hashtag.
GET/explore- Discover suggested people and trending hashtags.
GET/search?q=:query- Search public posts by text.
GET/bookmarks- List your bookmarks newest-bookmarked first. Optionally search them with
q. GET/firehose- Stream new posts as server-sent events.
VERB authentication bearer token required
Bookmarks
Bookmark mutations are idempotent. The private collection is ordered by when each post was bookmarked, newest first. Pass an optional q for full-text search and use the returned cursor for the next page.
curl -X POST 'https://textlog.cc/api/v1/posts/123/bookmark' -H "authorization: Bearer $TOKEN"
curl 'https://textlog.cc/api/v1/bookmarks?q=sqlite&limit=20' -H "authorization: Bearer $TOKEN"
curl -X DELETE 'https://textlog.cc/api/v1/posts/123/bookmark' -H "authorization: Bearer $TOKEN"
{"data":[{"id":123,"body":"A saved note","bookmarked_at":"2026-08-30T12:00:00Z","parent":null}],"pagination":{"next_cursor":null}}
Web-compatible threaded feeds
Use the /conversations variants when a client should render the same feed structure as the web app. The original endpoints remain flat, post- or activity-paginated collections for existing clients. Threaded feeds paginate conversations using the web page sizes 20, 40, 80, or 100.
curl 'https://textlog.cc/api/v1/feeds/all/conversations?limit=20'
curl 'https://textlog.cc/api/v1/feeds/hot/conversations?limit=20'
curl 'https://textlog.cc/api/v1/activities/my-feed/conversations?limit=20' \
-H "authorization: Bearer $TOKEN"
curl 'https://textlog.cc/api/v1/activities/@/conversations?limit=20' \
-H "authorization: Bearer $TOKEN"
Public threaded feeds return conversation objects containing the exact posts selected for that web feed page. Posts include parent_id, absolute depth, classification (root or reply), feed_ancestor_gap, unread, and directed_to_viewer. Follow each post’s parent relationship to build the visible reply tree.
{"data":[{"id":123,"posts":[{"id":123,"parent_id":null,"depth":0,"classification":"root"},{"id":140,"parent_id":123,"depth":1,"classification":"reply"}]}],"pagination":{"next_cursor":"opaque","previous_cursor":null}}
Personalized conversation feeds require a bearer token. Their ordered data array mixes conversation items with standalone typed activity items for user follows, hashtag follows, and signups. Conversation posts retain activity_id and activity_type (post, reply, or mention), so the existing activity read endpoints can mark them read.
Pass pagination.next_cursor or pagination.previous_cursor back as cursor. Reading these endpoints does not mark items read.
RSS and Atom
Feed collections are also available as RSS 2.0 or Atom 1.0. Add .rss or .atom to the collection address and enter it manually in a feed reader.
/feeds/all.rss
/feeds/hot.atom
/users/:handle/posts.rss
/tags/:tag/posts.atom
The all and hot feeds also have shorter root-level aliases:
/all.json
/all.rss
/all.atom
/hot.json
/hot.rss
/hot.atom
Signed-in users can generate private, personalized My Feed RSS and Atom URLs under Feed key in account security. These unguessable URLs are read-only, require no bearer header, and must be kept secret. Each key can be named, expired, or revoked independently. Personalized feeds are marked private and are not publicly cached.
/feeds/my-feed/:key.rss
/feeds/my-feed/:key.atom
The former latest, for-you, and to-me API and feed addresses remain available as backward-compatible aliases.
Public data archive
Download the latest daily, read-only snapshot as dump.zip. It contains paginated JSON files for public handles and bios, posts and reply links, translations, code execution outputs, locations, mentions, hashtags, and follow relationships. The accounts are frozen: the archive contains no bookmarks, login credentials, contact details, record timestamps, blocks, reports, deleted content, or other private data.
curl -O https://textlog.cc/dump.zip
Embeds
Add a read-only textlog card to any website with an iframe. Copy an example and replace the handle, hashtag, or post number. Feed embeds show the five newest notes and all links open textlog. See every format together on the live embed examples page.
<iframesrc="https://textlog.cc/embed/user/alice?theme=system&accent=sage&font=menlo"title="@alice on textlog"width="100%"height="520"loading="lazy"style="border:0"
></iframe>
<!-- all notes --><iframesrc="https://textlog.cc/embed/all?theme=dark&accent=purple"title="All notes on textlog"width="100%"height="520"style="border:0"></iframe><!-- hot notes --><iframesrc="https://textlog.cc/embed/hot?theme=light&accent=blue"title="Hot notes on textlog"width="100%"height="520"style="border:0"></iframe><!-- a hashtag --><iframesrc="https://textlog.cc/embed/tag/photography?theme=system&accent=theme"title="#photography on textlog"width="100%"height="520"style="border:0"></iframe><!-- one post --><iframesrc="https://textlog.cc/embed/post/123?theme=sepia&accent=rust"title="Post 123 on textlog"width="100%"height="220"style="border:0"></iframe>
Appearance uses the theme, accent, and font query parameters.
Themes: system, light, dark, sepia, and dracula.
Accents: theme, sage, purple, cyan, pink, amber, blue, and rust.
Fonts: system, sf, menlo, monaco, consolas, cascadia, courier, lucida, dejavu, liberation, ubuntu, noto, droid, source, roboto, fira, jetbrains, and hack.
Pagination
Collections accept limit from 1–100 (default 20). Pass the opaque pagination.next_cursor value back as cursor to fetch the next page. Replies include their immediate quoted post in parent, so displaying a feed needs no per-post follow-up requests.
curl 'https://textlog.cc/api/v1/feeds/all?limit=10'
curl 'https://textlog.cc/api/v1/activities/my-feed?limit=10' \
-H "authorization: Bearer $TOKEN"
Personalized activity collections return has_unread and typed activity objects. Each activity’s type is post, reply, mention, user_follow, tag_follow, or signup; payload contains the corresponding post or actor and target.
Explore has independent people_limit, people_cursor, tags_limit, and tags_cursor parameters. When a bearer token is supplied, reads include viewer relationship state and omit blocked people and hashtags.
Search
Search is public and uses the same prefix matching as the website. Separate words must all match.
curl 'https://textlog.cc/api/v1/search?q=quiet+notes&limit=10'
Firehose
The firehose is live-only and includes top-level posts and replies. Each new post arrives as a post event. Reconnects begin from that moment and do not replay missed events.
const events = new EventSource('https://textlog.cc/api/v1/firehose')
events.addEventListener('post', event => {
const post = JSON.parse(event.data)
})
Writing
Every account can use the write endpoints. Authenticate with a bearer token; no separate API access setting is required. For long-running integrations, generate a revocable API key.
Sign in with the code emailed alongside your magic link. Accounts are only created in a browser, so the API cannot sign anyone up.
curl -X POST https://textlog.cc/api/v1/auth/request \
-H 'content-type: application/json' -d '{"email":"you@example.com"}'
curl -X POST https://textlog.cc/api/v1/auth/verify \
-H 'content-type: application/json' -d '{"email":"you@example.com","code":"123456"}'
Posts include link previews and poll metadata. Live poll counts are hidden until you vote or the poll expires. Drafts support ordinary CRUD plus an atomic publish endpoint.
The returned token is an ordinary session. Both session tokens and generated API keys can be sent as bearer tokens and revoked under account security. Cookies are never accepted for writes.
curl -X POST https://textlog.cc/api/v1/posts \
-H "authorization: Bearer $TOKEN" \
-H 'content-type: application/json' -d '{"body":"hello from an app"}'
Limits and errors
API reads are limited to 120 requests per minute per IP. Writes are limited to 60 per hour per account, and posting keeps the same limit as the website: five posts every five minutes. A limited response uses 429 and includes Retry-After.
{"error":{"code":"not_found","message":"Post not found"}}