Luisearch
Public API
v1.0
Live

API Reference

Free, open search API powered by BM25 ranking. No API key required for public use.

Pages indexed
Unique terms
Domains
Images
Videos
Checking...
Crawler

Base URL

https://stevens-predictions-get-feet.trycloudflare.com

All endpoints accept JSON responses. CORS is enabled — you can call this API from any browser or server.

Authentication

Most endpoints work without authentication. An API key gives you attribution in the query logs and may unlock higher priority as the service grows.

How to include your key

Pass your key using either method:

# Query parameter GET /api/search?q=linux&key=ls_your_key_here # Authorization header GET /api/search?q=linux Authorization: Bearer ls_your_key_here
1
Request a key
Go to /register and fill in your name, email, and what you're building. Your key in ls_... format is generated and active immediately -- no approval wait.
2
Use your key
Pass it as ?key=ls_... or Authorization: Bearer ls_... on any request.
Passing an invalid key returns 401 Unauthorized. Omitting the key entirely works fine — unauthenticated requests are allowed.

Drive Auth API

The Drive API uses its own token-based auth flow separate from the main search API keys. Use these endpoints to obtain a Bearer token for Drive operations.

POST /api/drive/signup

Create a new Drive account. Returns a token immediately on success.

Request Body

{ "username": "alice", "password": "supersecret" }

Response

{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "username": "alice" }

POST /api/drive/login

Log in with existing credentials. Returns a fresh Bearer token.

Request Body

{ "username": "alice", "password": "supersecret" }

Response

{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "username": "alice" }

Using the Bearer token

Once you have a token, pass it as an Authorization header on all Drive API requests:

GET /api/drive/files Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... # Tokens do not expire by default but may be revoked by the admin.
Drive tokens are separate from search API keys. A search API key (ls_...) will not work as a Drive Bearer token.

Endpoints

GET /api/stats

Returns index statistics. Useful for showing users how large the index is.

Example Request

GET https://stevens-predictions-get-feet.trycloudflare.com/api/stats

Example Response

{ "pages": 5000, "terms": 123004 }
GET /api/hosts

Returns all indexed domains with their page counts, sorted by most pages. Up to 500 domains.

Example Request

GET https://stevens-predictions-get-feet.trycloudflare.com/api/hosts

Example Response

[ { "host": "en.wikipedia.org", "count": 124 }, { "host": "github.com", "count": 113 }, // ... ]
GET /api/crawl-status

Returns the URL currently being crawled, or null if the crawler is idle.

Example Response (active)

{ "url": "https://wiki.archlinux.org/title/Pacman", "crawling": true }

Example Response (idle)

{ "url": null, "crawling": false }
GET /api/image-stats

Returns the total number of images indexed.

Example Response

{ "images": 1200 }
GET /api/video-stats

Returns the total number of videos indexed.

Example Response

{ "videos": 1043 }
POST /api/keys/register

Request an API key. The key is generated and active immediately -- no manual approval needed.

Request Body (JSON)

FieldTypeDescription
name requiredstringYour name or app name
email requiredstringYour email address
usecase optionalstringWhat you're building

Example Request

POST https://stevens-predictions-get-feet.trycloudflare.com/api/keys/register Content-Type: application/json { "name": "Luis", "email": "luis@example.com", "usecase": "personal search widget" }

Example Response

{ "key": "ls_a1b2c3d4e5f6...", "status": "approved", "message": "Key approved." }
Save your key immediately after registering — it's only shown once. Use it right away as ?key=ls_....

More Core Search

GET/api/resurrect
If a URL is dead right now, hand back the last archived crawl of it (title/content) instead of a dead end.
ParamTypeRequiredDescription
urlstringrequiredFull http(s) URL to check

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/resurrect"

Response

{ "alive": false, "archived": true, "url": "https://example.com/page", "title": "Example Page", "content": "...(truncated to 6000 chars)...", "indexed_at": "2026-06-01 12:00:00" }
If the URL is actually still alive, returns {"alive": true} instead. 404 if dead and never archived.
GET/api/galaxy
Sampled pages from the index for the "Index Galaxy" 3D visualization.
ParamTypeRequiredDescription
limitintoptionalMax stars to sample, default 4000, capped at 8000

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/galaxy"

Response

{ "stars": [ { "id": 1023, "url": "https://example.com/", "title": "Example Domain", "host": "example.com" } ], "total": 2481932 }
GET/api/stats-history
Historical snapshots of index size over time (for growth charts).

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/stats-history"

Response

{ "snapshots": [ { "taken_at": "2026-07-01 00:00:00", "pages": 2481932, "sites": 41200, "images": 981234, "videos": 12044, "audio": 3021, "downloads": 8842 } ] }
GET/api/download-index
Streams the raw search-index.db SQLite file (~9GB), with HTTP Range support for resumable downloads.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/download-index"

Response

null
Not JSON — returns application/octet-stream with Accept-Ranges: bytes. Use curl -C - to resume.
GET/api/geo-map
Lat/lon + page counts for every indexed host that has been geolocated (backs the map visualization).

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/geo-map"

Response

{ "hosts": [ { "host": "example.com", "lat": 37.4, "lon": -122.1, "country": "United States", "city": "Mountain View", "pages": 142 } ] }
GET/api/geo-lookup
Real-time DNS + geolocation lookup for any domain (not just already-indexed ones); caches the result.
ParamTypeRequiredDescription
hoststringrequiredBare domain, e.g. example.com

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/geo-lookup"

Response

{ "host": "example.com", "ip": "93.184.216.34", "lat": 37.4, "lon": -122.1, "country": "United States", "city": "Mountain View", "pages": 0 }
400 if host is not a well-formed domain; 404 if DNS resolution fails; 502 if the geolocation provider fails.

More Auth / Keys

GET/api/dl-token
Set the shared download-manager access token (query param, not a header — simple by design).
ParamTypeRequiredDescription
tokenstringrequiredNew token value to store

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/dl-token"

Response

{ "ok": true }
GET/api/dl-token-check
Check whether a given token matches the currently configured download token.
ParamTypeRequiredDescription
tokenstringoptionalToken to verify

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/dl-token-check"

Response

{ "ok": true }
POST/api/admin/login
Admin console login — separate from both search API keys and Nexus/Drive accounts.

Auth: none (this endpoint issues the admin token)

ParamTypeRequiredDescription
usernamestringrequiredAdmin username
passwordstringrequiredAdmin password

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/login" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "token": "a1b2c3d4e5f6..." }
Internal/staff-only — not part of the public API contract.

Drive API

GET/api/drive/me
Current Drive account profile.

Auth: Bearer Drive token

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/me"

Response

{ "owner": "alice", "email": "alice@example.com", "quota": 10737418240, "used": 204838, "created_at": "2026-01-04 10:00:00" }
GET/api/drive/files
List files in a Drive folder.

Auth: Bearer Drive token

ParamTypeRequiredDescription
folderstringoptionalFolder path, default "/"

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/files"

Response

{ "files": [ { "id": "8f2a...", "name": "notes.txt", "size": 204, "mime": "text/plain", "folder": "/", "owner": "alice", "uploaded_at": "2026-06-01 09:00:00" } ], "used": 204838, "quota": 10737418240, "free": 10737213402 }
GET/api/drive/stats
Quota usage + file count summary.

Auth: Bearer Drive token

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/stats"

Response

{ "used": 204838, "quota": 10737418240, "free": 10737213402, "files": 12 }
GET/api/drive/trash
List files currently in trash (not yet permanently deleted).

Auth: Bearer Drive token

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/trash"

Response

{ "files": [ { "id": "8f2a...", "name": "old.txt", "trashed_at": "2026-07-10 08:00:00" } ] }
POST/api/drive/upload
Upload a file (multipart/form-data). Rejected if it exceeds the 1GB per-file cap or the account quota.

Auth: Bearer Drive token

ParamTypeRequiredDescription
filefilerequiredThe file
folderstringoptionalTarget folder, default "/"

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/upload" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "8f2a...", "name": "photo.jpg", "size": 204838, "mime": "image/jpeg" }
POST/api/drive/delete
Move a file to trash (soft delete).

Auth: Bearer Drive token

ParamTypeRequiredDescription
idstringrequiredFile id

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/delete" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/drive/restore
Restore a trashed file.

Auth: Bearer Drive token

ParamTypeRequiredDescription
idstringrequiredFile id

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/restore" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/drive/delete-permanent
Permanently delete a file and free its quota.

Auth: Bearer Drive token

ParamTypeRequiredDescription
idstringrequiredFile id

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/delete-permanent" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/drive/empty-trash
Permanently delete every trashed file for this account.

Auth: Bearer Drive token

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/empty-trash" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true, "deleted": 3 }
POST/api/drive/share
Toggle public sharing for a file; returns the public path when enabled.

Auth: Bearer Drive token

ParamTypeRequiredDescription
idstringrequiredFile id

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/share" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "shared": true, "path": "/api/drive/public/8f2a..." }
GET/api/drive/public/<id>
Fetch a file that its owner has marked shared — no auth required. 404 if not shared.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/public/<id>"

Response

null
GET/api/drive/download/<id>
Download one of your own Drive files (also accepts ?token= for plain <a download> links).

Auth: Bearer Drive token (or ?token=)

ParamTypeRequiredDescription
tokenstringoptionalDrive session token, alternative to the Authorization header

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/download/<id>"

Response

null
POST/api/drive/logout
Invalidate the current Drive Bearer token.

Auth: Bearer Drive token

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/drive/logout" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
GET/api/save-to-drive
Queue a URL for download into your token-scoped MYstuff folder via the local aria2c-web service.
ParamTypeRequiredDescription
urlstringrequiredURL to download
namestringoptionalFilename to save as
tokenstringoptionalDownload-manager token, required if one is configured

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/save-to-drive"

Response

{ "ok": true, "queued": { "gid": "a1b2c3" } }
502 if the local aria2c-web helper service is unreachable.
GET/api/drive-downloads
List active/queued downloads from the local aria2c-web helper.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/drive-downloads"

Response

{ "downloads": [ { "gid": "a1b2c3", "status": "active", "completedLength": 204800, "totalLength": 1048576 } ] }
GET/api/local-files
List files sitting in your token-scoped MYstuff download folder.
ParamTypeRequiredDescription
tokenstringoptionalDownload-manager token

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/local-files"

Response

{ "files": [ { "name": "ubuntu-24.04.iso", "size": 4831838208, "mtime": 1752345600.0 } ] }
GET/api/local-delete
Delete a file from your token-scoped MYstuff folder.
ParamTypeRequiredDescription
tokenstringoptionalDownload-manager token
namestringrequiredFilename to delete

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/local-delete"

Response

{ "ok": true }

More Media Search

GET/api/audio-stats
Total indexed audio clip count.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/audio-stats"

Response

{ "audio": 3021 }
GET/api/download-stats
Total indexed downloads + a per-category breakdown.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/download-stats"

Response

{ "downloads": 8842, "categories": { "linux": 3120, "ipsw": 940, "ipa": 210 } }
GET/api/downloads-crawl-status
Whether the downloads crawler is currently running, plus its last status line.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/downloads-crawl-status"

Response

{ "status": "crawling releases.ubuntu.com", "crawling": true }
GET/api/gifproxy
Server-side fetch of a remote GIF, bypassing hotlink/referer blocks.
ParamTypeRequiredDescription
ustringrequiredRemote GIF URL

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/gifproxy"

Response

null
Returns the raw image bytes, not JSON.
GET/api/gifvid
Transcode a remote (or crawled) GIF into a looping MP4 so it animates on iOS/all browsers.
ParamTypeRequiredDescription
ustringrequiredRemote GIF URL

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/gifvid"

Response

null
Returns video/mp4 bytes, not JSON.
GET/api/nexus/gifs
Search Luisearch's own crawled GIFs (verified actually-animated ones only); results come back as looping MP4 URLs.
ParamTypeRequiredDescription
qstringoptionalSearch text; empty returns a random set

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/gifs"

Response

{ "gifs": [ { "alt": "excited cat", "vid": "/api/gifvid?u=https%3A%2F%2Fexample.com%2Fcat.gif" } ] }

AI (Answers, Chat Tools, LuisPaper)

GET/api/ai-servers
List the AI "tool" backends available to the assistant/tool-use system.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/ai-servers"

Response

{ "servers": [ { "id": "web-search", "label": "Web Search", "icon": "\ud83d\udd0e", "desc": "Search the live index" } ] }
GET/api/ai/list
List saved AI chat conversations for the logged-in Drive account.

Auth: Bearer Drive token

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/ai/list"

Response

{ "conversations": [ { "id": "c1a2...", "title": "New chat", "updated_at": "2026-07-10 09:00:00" } ] }
GET/api/ai/get
Fetch one saved AI conversation with full message history.

Auth: Bearer Drive token

ParamTypeRequiredDescription
idstringrequiredConversation id

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/ai/get"

Response

{ "id": "c1a2...", "title": "New chat", "messages": [ { "role": "user", "content": "hello" } ] }
GET/api/paper
Synchronous quick-answer variant of LuisPaper — generates a short cited report from top search results without the job/poll flow.
ParamTypeRequiredDescription
qstringrequiredTopic to research

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/paper"

Response

{ "answer": "...report text...", "sources": [ { "url": "https://example.com/", "title": "..." } ] }
POST/api/paper/start
Start an async LuisPaper report job (retrieval + long-form generation runs in a background thread).

Auth: LuisPaper account (paper_ API key via Bearer/cookie)

ParamTypeRequiredDescription
qstringrequiredReport topic
lengthstringoptionalOne of the supported PAPER_LENGTHS, default "standard"

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/start" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "job_id": "7e2a..." }
401 if not logged in; 429 if the per-account rate limit is hit.
GET/api/paper/poll
Long-poll for new tokens on a report job/turn (up to 25s, returns as soon as new tokens or completion arrive).
ParamTypeRequiredDescription
job_idstringrequiredJob id from /api/paper/start
turnintoptionalTurn index, default latest
sinceintoptionalToken offset already received

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/poll"

Response

{ "tokens": [ "Linux", " is", " an", " open-source" ], "total": 842, "done": false, "error": null, "meta": { "title": "Linux: A Technical Overview" }, "turn": 0 }
POST/api/paper/followup
Continue a report conversation with a follow-up message (optionally with an attached image, routed through a vision model).

Auth: LuisPaper account

ParamTypeRequiredDescription
job_idstringrequiredJob id
messagestringrequiredFollow-up text
image_datastringoptionaldata: URL of an attached image

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/followup" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "turn": 2 }
GET/api/paper/suggestions
AI-suggested follow-up questions for a given report job.
ParamTypeRequiredDescription
job_idstringrequiredJob id

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/suggestions"

Response

{ "questions": [ "What distributions are most popular?", "How does it compare to BSD?" ] }
GET/api/paper/account/me
Current LuisPaper account username.

Auth: LuisPaper account

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/account/me"

Response

{ "username": "alice" }
POST/api/paper/account/signup
Create a LuisPaper account.
ParamTypeRequiredDescription
usernamestringrequired3+ chars, lowercase/digits/underscore
passwordstringrequired6+ chars

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/account/signup" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "username": "alice", "api_key": "paper_9c1f..." }
POST/api/paper/account/login
Log in to LuisPaper.
ParamTypeRequiredDescription
usernamestringrequired
passwordstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/account/login" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "username": "alice", "api_key": "paper_9c1f..." }
POST/api/paper/account/change-password
Change the logged-in LuisPaper account password.

Auth: LuisPaper account

ParamTypeRequiredDescription
current_passwordstringrequired
new_passwordstringrequired6+ chars

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/account/change-password" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
GET/api/paper/account/usage
Today's report-generation usage against the rate limit.

Auth: LuisPaper account

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/account/usage"

Response

{ "used_today": 3, "limit": 10, "window_seconds": 86400 }
GET/api/paper/history
List saved reports for the logged-in account (pinned first).

Auth: LuisPaper account

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/history"

Response

{ "reports": [ { "id": "r1", "topic": "linux kernel", "title": "Linux Kernel Overview", "custom_title": null, "pinned": false, "shared": false, "created_at": "2026-07-01 10:00:00" } ] }
GET/api/paper/history/report
Fetch one full saved report by id.

Auth: LuisPaper account

ParamTypeRequiredDescription
idstringrequiredReport id

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/history/report"

Response

{ "id": "r1", "topic": "linux kernel", "title": "Linux Kernel Overview", "raw_text": "...full report...", "pinned": false, "created_at": "2026-07-01 10:00:00" }
POST/api/paper/history/update
Rename (custom_title) or pin/unpin a saved report.

Auth: LuisPaper account

ParamTypeRequiredDescription
idstringrequired
custom_titlestringoptional
pinnedbooloptional

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/history/update" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/paper/history/delete
Delete a saved report.

Auth: LuisPaper account

ParamTypeRequiredDescription
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/history/delete" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/paper/history/share
Generate (or return the existing) public share token for a report.

Auth: LuisPaper account

ParamTypeRequiredDescription
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/history/share" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "token": "a9c1f..." }
POST/api/paper/history/unshare
Revoke a report's share token.

Auth: LuisPaper account

ParamTypeRequiredDescription
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/history/unshare" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
GET/api/paper/shared
Public, no-login read-only view of a shared report.
ParamTypeRequiredDescription
tokenstringrequiredShare token

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/paper/shared"

Response

{ "topic": "linux kernel", "title": "Linux Kernel Overview", "custom_title": null, "raw_text": "...", "created_at": "2026-07-01 10:00:00" }

Nexus — Auth

POST/api/vn/signup
Create a Voidnet/Nexus account (shared user system). Phone is required by the Nexus client but optional for Voidnet.
ParamTypeRequiredDescription
usernamestringrequired3+ chars
passwordstringrequired6+ chars
phonestringoptionalRequired by Nexus signup flow

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/signup" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "token": "a1b2...", "username": "alice" }
POST/api/vn/login
Log in to a Voidnet/Nexus account.
ParamTypeRequiredDescription
usernamestringrequired
passwordstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/login" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "token": "a1b2...", "username": "alice" }
POST/api/vn/logout
Invalidate the current session token.

Auth: Bearer session token

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/logout" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }

Nexus — Messaging

POST/api/nexus/messages
Post a message to a channel or a DM (channel_id can be a DM pseudo-channel).

Auth: vn session

ParamTypeRequiredDescription
channel_idstringrequired
contentstringoptionalUp to 4000 chars; required unless attachments/forward_of given
attachmentsarrayoptionalUp to 4 {type,url} objects
reply_tostringoptionalMessage id being replied to
forward_ofobjectoptional{author,content,attachments} of a forwarded message

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/messages" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "m1a2...", "channel_id": "c1", "author": "alice", "content": "hey!", "attachments": [], "reply_to": "", "created_at": "2026-07-19 10:00:00" }
GET/api/nexus/messages/<channel_id>
Fetch recent messages in a channel or DM (also supports forum thread replies via ?parent=).

Auth: vn session

ParamTypeRequiredDescription
parentstringoptionalForum root message id, to fetch just its thread

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/messages/<channel_id>"

Response

{ "messages": [ { "id": "m1", "author": "alice", "content": "hey!", "reactions": [] } ] }
POST/api/nexus/react
Toggle an emoji reaction on a message.

Auth: vn session

ParamTypeRequiredDescription
message_idstringrequired
emojistringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/react" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "reactions": [ { "emoji": "\ud83d\udc4d", "count": 2, "me": true } ] }
POST/api/nexus/delete
Delete a message (message author, or staff role in the server).

Auth: vn session

ParamTypeRequiredDescription
idstringrequiredMessage id

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/delete" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/nexus/typing
Broadcast a typing indicator to a channel/DM.

Auth: vn session

ParamTypeRequiredDescription
channel_idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/typing" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/nexus/poll/create
Create a poll, posted as a message with 2-10 options.

Auth: vn session

ParamTypeRequiredDescription
channel_idstringrequired
questionstringrequiredUp to 300 chars
optionsarrayrequired2-10 strings, each up to 120 chars

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/poll/create" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "m5...", "poll_id": "p1...", "content": "\ud83d\udcca Favorite distro?" }
POST/api/nexus/poll/vote
Cast or change a vote on a poll.

Auth: vn session

ParamTypeRequiredDescription
poll_idstringrequired
option_indexintrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/poll/vote" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "p1...", "question": "Favorite distro?", "options": [ { "text": "Arch", "votes": 4 }, { "text": "Debian", "votes": 2 } ], "total_votes": 6 }

Nexus — Channels & Servers

POST/api/nexus/servers
Create a new server (with a default "general" text channel, creator becomes owner).

Auth: vn session

ParamTypeRequiredDescription
namestringrequiredUp to 60 chars
iconstringoptionalEmoji or image URL

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/servers" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "s1a2...", "name": "My Server", "invite": "ab12cd34" }
GET/api/nexus/servers
Servers the logged-in user is a member of (plus the default Lobby).

Auth: vn session

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/servers"

Response

{ "servers": [ { "id": "lobby", "name": "Lobby", "icon": "\ud83c\udf10", "invite": "", "owner": "system" } ] }
POST/api/nexus/join
Join a server via invite code.

Auth: vn session

ParamTypeRequiredDescription
invitestringrequiredInvite code or server id

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/join" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "s1a2...", "name": "My Server" }
POST/api/nexus/leave
Leave a server (owner cannot leave; must transfer or delete instead).

Auth: vn session

ParamTypeRequiredDescription
server_idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/leave" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/nexus/kick
Remove a member from a server (requires owner/admin/mod, cannot kick equal-or-higher role).

Auth: vn session

ParamTypeRequiredDescription
server_idstringrequired
usernamestringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/kick" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/nexus/role
Set a member's role (owner/admin only; cannot change the owner).

Auth: vn session

ParamTypeRequiredDescription
server_idstringrequired
usernamestringrequired
rolestringrequiredadmin | mod | member

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/role" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/nexus/channels
Create a channel in a server.

Auth: vn session

ParamTypeRequiredDescription
server_idstringrequired
namestringrequiredLowercased, spaces become dashes
typestringoptionaltext|image|stream|event|announcement|forum, default text
topicstringoptionalUp to 120 chars

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/channels" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "c9a1...", "name": "general" }
GET/api/nexus/channels/<server_id>
List channels in a server (member-only).

Auth: vn session

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/channels/<server_id>"

Response

{ "channels": [ { "id": "c1", "name": "general", "topic": "", "position": 0, "type": "text" } ] }
GET/api/nexus/members/<server_id>
List a server's members with role/profile/online status.

Auth: vn session

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/members/<server_id>"

Response

{ "members": [ { "username": "alice", "role": "owner", "avatar": "", "color": "", "online": true } ] }
POST/api/nexus/server/icon
Set a server's icon (owner/admin only).

Auth: vn session

ParamTypeRequiredDescription
server_idstringrequired
iconstringrequiredEmoji or image URL, up to 300 chars

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/server/icon" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true, "icon": "\ud83d\ude80" }
POST/api/nexus/profile
Set your own Nexus profile (partial updates supported).

Auth: vn session

ParamTypeRequiredDescription
avatarstringoptional
colorstringoptional
biostringoptional
statusstringoptional
pronounsstringoptional
banner_colorstringoptional

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/profile" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true, "avatar": "", "color": "#8ab4f8", "bio": "hi", "status": "", "pronouns": "", "banner_color": "" }
GET/api/nexus/profile/<username>
Fetch any user's public Nexus profile.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/profile/<username>"

Response

{ "username": "alice", "avatar": "", "color": "#8ab4f8", "bio": "hi" }

Nexus — DMs

POST/api/nexus/dm/open
Resolve a username into a deterministic DM channel id.

Auth: vn session

ParamTypeRequiredDescription
usernamestringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/dm/open" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "channel_id": "dm:alice:bob", "user": "bob" }
GET/api/nexus/dms
List your DM conversations, latest message first, with online status.

Auth: vn session

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/dms"

Response

{ "dms": [ { "channel_id": "dm:alice:bob", "user": "bob", "last": "hey!", "at": "2026-07-19 10:00:00", "online": true, "avatar": "", "color": "" } ] }

Nexus — Realtime (WebSocket + long-poll)

WS/api/nexus/ws
WebSocket realtime feed — the primary transport for live Nexus events (messages, presence, typing, reactions, calls, etc). Replaces long-polling when available.
ParamTypeRequiredDescription
tokenstringrequiredvn session token, passed in the connect URL query string

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/ws"

Response

null
Connect to wss://luisearch.pages.dev/api/nexus/ws?token=YOUR_TOKEN (ws:// only over the plain tunnel). First frame received is {"type":"ready","cursor":<n>}, after which the server pushes JSON event frames as they happen. Event "type" values seen from nx_broadcast() calls across the codebase: message, dm, reaction, delete, typing, members, channels, poll_update, presence, profile, server, signal, live, event, call_incoming, call_response, call_signal, call_ended, login_request, wifi_login_request.
GET/api/nexus/events
Legacy long-poll fallback realtime feed (same event shapes as the WebSocket), used when WS isn't available.
ParamTypeRequiredDescription
tokenstringrequired
afterintoptionalCursor from the previous call; omit/-1 to bootstrap and just get the current cursor

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/events"

Response

{ "cursor": 4821, "events": [ { "type": "message", "channel_id": "c1", "message": { "id": "m1", "author": "alice", "content": "hey" } } ] }
Blocks server-side for up to 25s waiting for new events before returning.

Nexus — Calls & RTC

POST/api/nexus/call/start
Ring another user for a voice or screen-share call.

Auth: vn session

ParamTypeRequiredDescription
usernamestringrequiredCallee
kindstringoptionalvoice|screen, default voice

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/call/start" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "call_id": "a1b2..." }
POST/api/nexus/call/respond
Callee accepts or declines an incoming call.

Auth: vn session

ParamTypeRequiredDescription
call_idstringrequired
acceptboolrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/call/respond" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "status": "accepted" }
POST/api/nexus/call/signal
Relay a WebRTC SDP offer/answer/ICE candidate between the two call participants.

Auth: vn session

ParamTypeRequiredDescription
call_idstringrequired
dataobjectrequiredOpaque SDP/ICE payload

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/call/signal" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/nexus/call/end
End an active call (either side).

Auth: vn session

ParamTypeRequiredDescription
call_idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/call/end" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/nexus/signal
WebRTC signaling relay for in-channel screen share (separate from the call/* flow).

Auth: vn session

ParamTypeRequiredDescription
tostringrequiredTarget username
channel_idstringoptional
kindstringoptional
dataobjectoptional

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/signal" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/nexus/live
Start or stop screen-sharing presence in a channel.

Auth: vn session

ParamTypeRequiredDescription
channel_idstringrequired
onboolrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/live" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true, "live": [ "alice" ] }
GET/api/nexus/live/<channel_id>
Who is currently screen-sharing in a channel.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/live/<channel_id>"

Response

{ "live": [ "alice" ] }
POST/api/nexus/rtc/signal
Room-code-keyed WebRTC signaling relay (used by the desktop/phone pairing flow, not usernames).
ParamTypeRequiredDescription
roomstringrequiredUp to 16 chars
fromstringrequireddesktop|phone
dataobjectoptional

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/rtc/signal" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
GET/api/nexus/rtc/poll
Drain queued signaling messages for one side of a paired room.
ParamTypeRequiredDescription
roomstringrequired
rolestringrequireddesktop|phone

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/rtc/poll"

Response

{ "msgs": [] }

Nexus — QR / Push / WiFi Sign-in

POST/api/nexus/qr/new
Desktop requests a new QR login code.
ParamTypeRequiredDescription
shortbooloptionalUse a short 4-char code for the "light" login flow

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/qr/new" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "code": "a1b2c3d4e5" }
POST/api/nexus/qr/approve
A logged-in phone approves a QR code, minting a new session token for the desktop.

Auth: vn session

ParamTypeRequiredDescription
codestringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/qr/approve" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true, "username": "alice" }
GET/api/nexus/qr/img
SVG QR code image for a login/pair code.
ParamTypeRequiredDescription
cstringrequiredCode
mstringoptionalsignup|pair|(login)

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/qr/img"

Response

null
Returns image/svg+xml, not JSON.
GET/api/nexus/qr/poll
Desktop polls whether its QR code has been approved yet.
ParamTypeRequiredDescription
cstringrequiredCode

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/qr/poll"

Response

{ "approved": true, "token": "a1b2...", "username": "alice" }
POST/api/nexus/push/request
Desktop asks a specific user's logged-in phone(s) to approve a login.
ParamTypeRequiredDescription
usernamestringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/push/request" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "r1a2b3" }
POST/api/nexus/push/respond
Phone approves or denies a pending push login request.

Auth: vn session

ParamTypeRequiredDescription
idstringrequired
okboolrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/push/respond" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
GET/api/nexus/push/poll
Desktop polls the status of its push login request.
ParamTypeRequiredDescription
idstringrequired

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/push/poll"

Response

{ "status": "approved", "token": "a1b2...", "username": "alice" }
POST/api/nexus/wifi/new
New (logged-out) device registers itself and learns which logged-in devices are nearby on the same network.

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/wifi/new" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "device_id": "d1a2...", "nearby": [ "alice" ] }
POST/api/nexus/wifi/announce
Logged-in device announces "I'm here on this network" so new devices can discover it.

Auth: vn session

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/wifi/announce" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/nexus/wifi/request
New device asks nearby phones to sign it in.
ParamTypeRequiredDescription
device_idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/wifi/request" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "nearby": [ "alice" ] }
POST/api/nexus/wifi/approve
Phone approves a nearby device's sign-in request (must be on the same detected network).

Auth: vn session

ParamTypeRequiredDescription
device_idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/wifi/approve" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
403 if the approving phone is not on the same network as the requesting device.
GET/api/nexus/wifi/poll
New device polls for approval.
ParamTypeRequiredDescription
dstringrequireddevice_id

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/wifi/poll"

Response

{ "approved": true, "token": "a1b2...", "username": "alice" }

Nexus — Media

POST/api/nexus/upload
Upload an image for use in a message; returns its relative URL.

Auth: vn session

ParamTypeRequiredDescription
filefilerequiredpng/jpg/jpeg/gif/webp, max 12MB

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/upload" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "url": "/api/img/9c1f...jpg" }
POST/api/nexus/transcribe
Transcribe a voice-message clip to text via a local Whisper service.

Auth: vn session

ParamTypeRequiredDescription
audiofilerequiredAudio clip, max 25MB

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/transcribe" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "text": "hey, are you free later?" }
502 if the local Whisper Docker container is unreachable.
GET/api/img/<id>
Serve a previously uploaded image by id (proxied, reachable on the apex domain).

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/img/<id>"

Response

null
Returns raw image bytes, not JSON.
POST/api/img/upload
Public image host — upload an image and get back a full shareable URL (not Nexus-scoped, no auth).
ParamTypeRequiredDescription
filefilerequiredpng/jpg/jpeg/gif/webp, max 12MB

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/img/upload" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "url": "/api/img/9c1f...jpg", "full": "https://luisearch.pages.dev/api/img/9c1f...jpg" }

Nexus — Events

POST/api/nexus/events/create
Create a structured event (date/location) in a channel.

Auth: vn session

ParamTypeRequiredDescription
channel_idstringrequired
titlestringrequiredUp to 120 chars
whenstringoptional
locationstringoptional
descriptionstringoptional

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/events/create" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "e1a2..." }
POST/api/nexus/events/rsvp
RSVP to an event.

Auth: vn session

ParamTypeRequiredDescription
event_idstringrequired
statusstringrequiredgoing|maybe|no

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/events/rsvp" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
GET/api/nexus/events/<channel_id>
List events in a channel with RSVP tallies and your own RSVP.

Auth: vn session

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/nexus/events/<channel_id>"

Response

{ "events": [ { "id": "e1", "title": "Game night", "rsvp": { "going": 4, "maybe": 1, "no": 0 }, "my_rsvp": "going" } ] }

Voidnet (Social Feed)

GET/api/vn/feed
Paginated, score-ranked Voidnet post feed.
ParamTypeRequiredDescription
offsetintoptionaldefault 0
limitintoptionaldefault 20, max 50

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/feed"

Response

{ "posts": [ { "id": "p1", "author": "alice", "text": "hello voidnet", "media": [], "like_count": 4, "my_vote": 0 } ], "total": 812 }
POST/api/vn/post
Create a Voidnet post (multipart with up to 4 files, or plain JSON text-only).

Auth: vn session

ParamTypeRequiredDescription
textstringoptional
file0..file3fileoptionalUp to 4 attachments

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/post" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "p1a2..." }
GET/api/vn/post/<id>
Fetch a post with its comment thread.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/post/<id>"

Response

{ "post": { "id": "p1", "text": "hello", "my_vote": 0 }, "comments": [ { "id": "c1", "author": "bob", "text": "nice!", "my_vote": 0 } ] }
POST/api/vn/post/delete
Delete your own post (and its attached media files).

Auth: vn session

ParamTypeRequiredDescription
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/post/delete" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/vn/comment
Comment on a post (optionally as a reply to another comment).

Auth: vn session

ParamTypeRequiredDescription
post_idstringrequired
parent_idstringoptional
textstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/comment" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "c1a2..." }
POST/api/vn/vote
Upvote/downvote/clear a vote on a post or comment.

Auth: vn session

ParamTypeRequiredDescription
idstringrequired
typestringrequiredpost|comment
voteintrequired1, -1, or 0

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/vote" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/vn/follow
Follow or unfollow a user.

Auth: vn session

ParamTypeRequiredDescription
usernamestringrequired
actionstringoptionalfollow (default) | unfollow

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/follow" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
GET/api/vn/me
Current Voidnet profile.

Auth: vn session

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/me"

Response

{ "username": "alice", "bio": "", "follower_count": 12, "following_count": 4 }
GET/api/vn/profile/<username>
Public Voidnet profile for any user, with their recent posts.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/profile/<username>"

Response

{ "username": "alice", "bio": "", "posts": [ { "id": "p1", "text": "hi" } ], "following": false }
POST/api/vn/profile/update
Update your own bio/sysinfo/banner/status/links.

Auth: vn session

ParamTypeRequiredDescription
biostringoptional
sysinfoobjectoptional
bannerstringoptional
banner_imgstringoptional
statusstringoptional
linksobjectoptional

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/profile/update" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/vn/profile/avatar
Upload a profile avatar image (multipart).

Auth: vn session

ParamTypeRequiredDescription
filefilerequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/profile/avatar" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "avatar_id": "9c1f...jpg" }
POST/api/vn/profile/banner
Upload a profile banner image (multipart).

Auth: vn session

ParamTypeRequiredDescription
filefilerequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/profile/banner" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "banner_img": "9c1f...jpg" }
POST/api/vn/dm/send
Send a plain Voidnet DM (separate from the richer Nexus DM/messages system).

Auth: vn session

ParamTypeRequiredDescription
tostringrequired
textstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/dm/send" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "m1a2..." }
GET/api/vn/dm/inbox
List Voidnet DM conversations with unread counts.

Auth: vn session

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/dm/inbox"

Response

{ "conversations": [ { "other": "bob", "last_time": "2026-07-19 10:00:00", "unread": 2 } ] }
GET/api/vn/dm/conversation/<user>
Fetch (and mark read) the DM history with one user.

Auth: vn session

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/dm/conversation/<user>"

Response

{ "messages": [ { "id": "m1", "sender": "alice", "recipient": "bob", "text": "hey", "read": 1 } ] }
GET/api/vn/notifications
Recent notifications (likes, comments, follows, DMs) with unread count.

Auth: vn session

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/notifications"

Response

{ "notifications": [ { "id": "n1", "type": "like", "from_user": "bob", "created_at": "2026-07-19 10:00:00" } ], "unread": 3 }
POST/api/vn/notifications/read
Mark all notifications as read.

Auth: vn session

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/notifications/read" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/vn/push/subscribe
Register a Web Push subscription for notifications.

Auth: vn session

ParamTypeRequiredDescription
subscriptionobjectrequiredStandard PushSubscription JSON

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/push/subscribe" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/vn/push/unsubscribe
Remove all Web Push subscriptions for this account.

Auth: vn session

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/push/unsubscribe" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
GET/api/vn/vapid-public-key
Public VAPID key needed to create a Web Push subscription client-side.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/vn/vapid-public-key"

Response

{ "key": "BEl62iUYgUiv..." }

Voidgroups (Group Chats)

POST/api/voidgroups/create
Create a group chat (creator becomes owner).

Auth: vn session

ParamTypeRequiredDescription
namestringrequired
descriptionstringoptional

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/voidgroups/create" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "g1a2...", "name": "Linux Fans" }
POST/api/voidgroups/join
Join an existing group.

Auth: vn session

ParamTypeRequiredDescription
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/voidgroups/join" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
POST/api/voidgroups/leave
Leave a group.

Auth: vn session

ParamTypeRequiredDescription
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/voidgroups/leave" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
GET/api/voidgroups/list
List groups, largest first, with your membership status.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/voidgroups/list"

Response

{ "groups": [ { "id": "g1", "name": "Linux Fans", "member_count": 42, "is_member": true } ] }
POST/api/voidgroups/post
Post a message to a group (multipart with up to 4 files, or plain JSON text-only).

Auth: vn session

ParamTypeRequiredDescription
group_idstringrequired
textstringoptional
file0..file3fileoptional

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/voidgroups/post" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "id": "m1a2..." }
GET/api/voidgroups/messages/<group_id>
Fetch recent messages in a group.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/voidgroups/messages/<group_id>"

Response

{ "messages": [ { "id": "m1", "author": "alice", "text": "hey all" } ] }

LuisWiki

GET/api/wiki/list
List all wiki pages.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/wiki/list"

Response

{ "pages": [ { "slug": "linux-basics", "title": "Linux Basics", "updated_at": "2026-06-01 10:00:00" } ] }
GET/api/wiki/page
Fetch a wiki page by slug, rendered to HTML.
ParamTypeRequiredDescription
slugstringrequired

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/wiki/page"

Response

{ "exists": true, "slug": "linux-basics", "title": "Linux Basics", "content": "# Linux Basics\\n...", "html": "<h1>Linux Basics</h1>...", "editor": "alice", "updated_at": "2026-06-01 10:00:00" }
Returns {"exists": false, "slug": "..."} with 404 if the page doesn't exist yet.

Code Runner

GET/api/code/list
List saved code projects for the logged-in user.

Auth: vn session

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/code/list"

Response

{ "projects": [ { "id": "p1", "name": "Untitled project", "lang": "python", "updated_at": "2026-07-01 10:00:00" } ] }
GET/api/code/load
Load a saved code project by id.

Auth: vn session

ParamTypeRequiredDescription
idstringrequired

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/code/load"

Response

{ "id": "p1", "name": "Untitled project", "lang": "python", "code": "print(\"hi\")" }

App Store

GET/api/appstore/catalog
List published apps in the community app store.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/appstore/catalog"

Response

{ "apps": [ { "id": "a1", "name": "MyApp", "subtitle": "A cool app", "version": "1.0", "icon": "app.fill", "publisher": "alice", "desc": "...", "ipaURL": "https://luisearch.pages.dev/api/appstore/ipa/a1" } ] }
GET/api/appstore/generate/status
Poll the build status of an AI-generated app job.
ParamTypeRequiredDescription
jobstringrequiredJob/session id from /api/appstore/generate

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/appstore/generate/status"

Response

{ "status": "building" }
status can be "building", "failure", or a completed build response; 404 for an unknown job.

Admin (internal, staff-only)

POST/api/admin/approve
Approve a pending API key.

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequiredAdmin session token
idstringrequiredKey id

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/approve" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
POST/api/admin/reject
Reject a pending API key.

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequired
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/reject" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
POST/api/admin/revoke
Permanently delete an API key.

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequired
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/revoke" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
POST/api/admin/bulk-approve
Approve every currently pending API key at once.

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/bulk-approve" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "approved": 7 }
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
POST/api/admin/change-password
Change the admin console password.

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequired
old_passwordstringrequired
new_passwordstringrequired6+ chars

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/change-password" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
GET/api/admin/keys
List every registered API key (all statuses).

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequired

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/keys"

Response

[ { "id": "k1", "key": "ls_9c1f...", "name": "alice", "email": "alice@example.com", "status": "approved" } ]
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
POST/api/admin/webmaster/approve
Approve a webmaster crawl-submission and queue it into the live crawler.

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequired
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/webmaster/approve" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
POST/api/admin/webmaster/force-crawl
Force-approve and immediately queue a submission for the crawler.

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequired
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/webmaster/force-crawl" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
POST/api/admin/webmaster/reject
Reject a webmaster submission.

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequired
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/webmaster/reject" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
POST/api/admin/webmaster/delete
Delete a webmaster submission record.

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequired
idstringrequired

Example

curl -X POST "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/webmaster/delete" \ -H "Content-Type: application/json" \ -d '{...}'

Response

{ "ok": true }
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
GET/api/admin/webmaster/list
List all webmaster submissions with live index status.

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequired

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/webmaster/list"

Response

[ { "id": "s1", "name": "Alice", "email": "alice@example.com", "url": "https://example.com/", "status": "approved", "indexed": true, "indexed_pages": 42 } ]
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
GET/api/admin/logs
Recent search query log (last 200), joined with the API key that made each request.

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequired

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/admin/logs"

Response

[ { "id": 1, "query": "linux kernel", "results_count": 24, "created_at": "2026-07-19 10:00:00", "key_name": "alice", "key_email": "alice@example.com" } ]
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
GET/api/crawl/start
Start a crawl run (optionally seeded from a specific URL).

Auth: admin session

ParamTypeRequiredDescription
tokenstringrequiredAdmin session token
urlstringoptionalSeed URL; omit to crawl from sitemaps

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/crawl/start"

Response

{ "started": true, "pid": 48213, "seed": "sitemaps" }
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness.
GET/api/crawl/stop
Kill any running crawler process.

Example

curl "https://stevens-predictions-get-feet.trycloudflare.com/api/crawl/stop"

Response

{ "stopped": 1 }
Internal, staff-only. Requires an admin session token from /api/admin/login. Not part of the public API contract — documented here only for completeness. (no token check in this handler — treat as staff-only by convention.)

Response Schema

Each result object in the /api/search response contains these fields:

FieldTypeDescription
idintegerInternal page ID in the index
urlstringFull URL of the indexed page
titlestringPage title from the HTML <title> tag
snippetstringFirst 300 characters of the page content

Error Codes

All errors are returned as JSON with an error field. Below is the full reference.

StatusMeaningDescription
400Bad RequestMissing or invalid required parameters (e.g. missing q or missing name/email in register)
401UnauthorizedInvalid, pending, or missing API key on an authenticated endpoint
404Not FoundThe endpoint path does not exist
402Rate LimitedToo many requests in a short window — check retry_after in the response and wait
500Server ErrorInternal error (e.g. DB unavailable).

Example Error Bodies

400 Bad Request

"error": "q parameter is required"

401 Unauthorized

"error": "Invalid or pending API key"

429 Rate Limited

{ "error": "Rate limit exceeded", "retry_after": 60 }

500 Server Error

{ "error": "Internal server error", "fallback": true }
All errors are returned as JSON: {"error": "message here"}

Rate Limits

Rate limits apply per IP per 60-second window on search endpoints (/api/search, /api/image-search, /api/video-search).

Tier Requests / min How to get
Anonymous 20 No key required
Free API Key 120 Register below — free
Plus Unlimited Manually granted

When the limit is exceeded the API returns 402 with a JSON body:

HTTP/1.1 402 Payment Required Content-Type: application/json { "error": "rate_limit_exceeded", "message": "💳 Your vibe has been declined. Try again in 60s.", "retry_after": 58, "tier": "none", "upgrade": "https://luisearch.pages.dev/docs#register" }
Stats endpoints (/api/stats, /api/image-stats, /api/video-stats, /api/hosts) are not rate limited.

How it works

1
Deep Crawler
Starts from 500+ seed URLs + 14 sitemaps and follows every link via BFS traversal. Stores page title, content (capped at 5KB), and URL into SQLite on an external SSD. No per-host limit — it crawls entire domains. Stop words and short terms are filtered before indexing to keep the DB lean.
2
BM25 + Title Boost + Host Boost
Pages are scored using BM25 (the same algorithm Elasticsearch and Solr use). Title matches get +3 per term. Host name matches get +10 per term — so searching "docker" surfaces docs.docker.com above everything else. Returns up to 200 results.
3
Image Crawler
A separate image crawler visits already-indexed pages and extracts <img> tags with meaningful alt text. Images go into a separate images.db and are searchable via /api/image-search. Priority is given to image-rich hosts like Apple, The Verge, and iFixit.

Stack: Python · SQLite · BM25 · Cloudflare Pages · Cloudflare Tunnel · Mobile PWA

Changelog

June 2026
Video Search New
Launched /api/video-search and /api/video-stats — a dedicated video crawler indexes 1,000+ YouTube videos (title, thumbnail, duration, channel) into a separate videos.db. New 🎬 Videos tab on the homepage.
June 2026
Drive Auth API New
Added Drive API with token-based authentication: POST /api/drive/signup and POST /api/drive/login endpoints for Bearer token flow.
May 2026
200 Results Per Query
Raised the maximum result count from 50 to 200. BM25 scoring now returns up to 200 candidates before AI reranking.
April 2026
Image Search New
Launched /api/image-search — a separate image crawler indexes <img> alt text from crawled pages into images.db. 6,900+ images indexed.
March 2026
Host Name Boost
Queries matching a domain name now get a +10 per-term boost, surfacing official sites (e.g. docs.docker.com for "docker") to the top.
February 2026
AI Reranking
Integrated llama3.2:1b via Ollama for semantic reranking of the top 20 BM25 candidates. Falls back to BM25 order on timeout.
January 2026
Public API Launch v1.0
First public release of the Luisearch API. Core endpoints: /api/search, /api/stats, /api/hosts, /api/crawl-status.

Code Examples

JavaScript
TypeScript
Python
curl
Go
Rust
PHP
Bash
C++
Java
Swift
Ruby
C#
Kotlin
// Fetch search results async function search(query, apiKey = null) { const url = new URL('https://stevens-predictions-get-feet.trycloudflare.com/api/search'); url.searchParams.set('q', query); if (apiKey) url.searchParams.set('key', apiKey); const res = await fetch(url); if (!res.ok) throw new Error(await res.text()); return res.json(); } const data = await search('linux kernel'); data.results.forEach(r => console.log(r.title, r.url));
interface SearchResult { id: number; url: string; title: string; snippet: string; } interface SearchResponse { results: SearchResult[]; } async function search(query: string, apiKey?: string): Promise<SearchResponse> { const url = new URL('https://stevens-predictions-get-feet.trycloudflare.com/api/search'); url.searchParams.set('q', query); if (apiKey) url.searchParams.set('key', apiKey); const res = await fetch(url.toString()); if (!res.ok) throw new Error(await res.text()); return res.json(); } const data = await search('linux kernel'); data.results.forEach(r => console.log(r.title, r.url));
import requests def search(query: str, api_key: str = None) -> list: params = {"q": query} if api_key: params["key"] = api_key res = requests.get( "https://stevens-predictions-get-feet.trycloudflare.com/api/search", params=params, timeout=15 ) res.raise_for_status() return res.json()["results"] results = search("linux kernel") for r in results: print(r["title"], "-", r["url"])
# Basic search curl "https://stevens-predictions-get-feet.trycloudflare.com/api/search?q=linux+kernel" # With API key (query param) curl "https://stevens-predictions-get-feet.trycloudflare.com/api/search?q=linux&key=ls_your_key" # With API key (header) curl -H "Authorization: Bearer ls_your_key" \ "https://stevens-predictions-get-feet.trycloudflare.com/api/search?q=linux" # Pretty print with jq curl -s "https://stevens-predictions-get-feet.trycloudflare.com/api/search?q=linux" | jq '.results[].title'
package main import ( "encoding/json" "fmt" "net/http" "net/url" ) type Result struct { ID int `json:"id"` URL string `json:"url"` Title string `json:"title"` Snippet string `json:"snippet"` } type Response struct { Results []Result `json:"results"` } func search(query string) ([]Result, error) { params := url.Values{"q": {query}} resp, err := http.Get("https://stevens-predictions-get-feet.trycloudflare.com/api/search?" + params.Encode()) if err != nil { return nil, err } defer resp.Body.Close() var data Response json.NewDecoder(resp.Body).Decode(&data) return data.Results, nil } func main() { results, _ := search("linux kernel") for _, r := range results { fmt.Printf("%s\n %s\n\n", r.Title, r.URL) } }
// Cargo.toml: reqwest = { features = ["json"] }, tokio, serde, serde_json use serde::Deserialize; #[derive(Deserialize, Debug)] struct SearchResult { url: String, title: String, snippet: String, } #[derive(Deserialize)] struct SearchResponse { results: Vec<SearchResult>, } #[tokio::main] async fn main() -> Result<(), Box<dyn std::error::Error>> { let resp: SearchResponse = reqwest::get( "https://stevens-predictions-get-feet.trycloudflare.com/api/search?q=linux+kernel" ).await?.json().await?; for r in &resp.results { println!("{}\n {}\n", r.title, r.url); } Ok(()) }
<?php function luisearch(string $query, string $apiKey = ''): array { $url = 'https://stevens-predictions-get-feet.trycloudflare.com/api/search?q=' . urlencode($query); if ($apiKey) $url .= '&key=' . urlencode($apiKey); $ctx = stream_context_create(['http' => ['timeout' => 15]]); $raw = file_get_contents($url, false, $ctx); $data = json_decode($raw, true); return $data['results'] ?? []; } $results = luisearch('linux kernel'); foreach ($results as $r) { echo $r['title'] . ' - ' . $r['url'] . "\n"; } ?>
#!/bin/bash QUERY="${1:-linux}" API_KEY="${2:-}" URL="https://stevens-predictions-get-feet.trycloudflare.com/api/search?q=$(python3 -c "import urllib.parse,sys; print(urllib.parse.quote(sys.argv[1]))" "$QUERY")" [ -n "$API_KEY" ] && URL="${URL}&key=${API_KEY}" curl -s "$URL" | python3 -c " import json, sys data = json.load(sys.stdin) for r in data['results']: print(r['title']) print(' ', r['url']) print() "
// g++ search.cpp -lcurl -o search #include <iostream> #include <string> #include <curl/curl.h> static size_t write_cb(char* d, size_t s, size_t n, std::string* out) { out->append(d, s * n); return s * n; } std::string luisearch(const std::string& query) { CURL* curl = curl_easy_init(); std::string response; std::string url = "https://stevens-predictions-get-feet.trycloudflare.com/api/search?q=" + query; curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response); curl_easy_setopt(curl, CURLOPT_TIMEOUT, 15L); curl_easy_perform(curl); curl_easy_cleanup(curl); return response; } int main() { std::cout << luisearch("linux+kernel") << std::endl; }
import java.net.URI; import java.net.URLEncoder; import java.net.http.*; import java.nio.charset.StandardCharsets; public class Luisearch { static final String BASE = "https://stevens-predictions-get-feet.trycloudflare.com"; public static String search(String query) throws Exception { String encoded = URLEncoder.encode(query, StandardCharsets.UTF_8); HttpClient client = HttpClient.newHttpClient(); HttpRequest req = HttpRequest.newBuilder() .uri(URI.create(BASE + "/api/search?q=" + encoded)) .timeout(java.time.Duration.ofSeconds(15)) .build(); HttpResponse<String> res = client.send(req, HttpResponse.BodyHandlers.ofString()); return res.body(); } public static void main(String[] args) throws Exception { System.out.println(search("linux kernel")); } }
import Foundation struct SearchResult: Codable { let id: Int let url: String let title: String let snippet: String } struct SearchResponse: Codable { let results: [SearchResult] } func luisearch(_ query: String) async throws -> [SearchResult] { var components = URLComponents(string: "https://stevens-predictions-get-feet.trycloudflare.com/api/search")! components.queryItems = [URLQueryItem(name: "q", value: query)] let (data, _) = try await URLSession.shared.data(from: components.url!) return try JSONDecoder().decode(SearchResponse.self, from: data).results } let results = try await luisearch("linux kernel") for r in results { print(r.title, r.url) }
require 'net/http' require 'uri' require 'json' def luisearch(query, api_key: nil) uri = URI('https://stevens-predictions-get-feet.trycloudflare.com/api/search') params = { q: query } params[:key] = api_key if api_key uri.query = URI.encode_www_form(params) res = Net::HTTP.get_response(uri) raise "Error #{res.code}" unless res.is_a?(Net::HTTPSuccess) JSON.parse(res.body)['results'] end results = luisearch('linux kernel') results.each { |r| puts "#{r['title']}\n #{r['url']}\n" }
using System.Net.Http.Json; using System.Text.Json; record SearchResult(int Id, string Url, string Title, string Snippet); record SearchResponse(SearchResult[] Results); async Task<SearchResult[]> Luisearch(string query, string? apiKey = null) { using var client = new HttpClient(); var url = $"https://stevens-predictions-get-feet.trycloudflare.com/api/search?q={Uri.EscapeDataString(query)}"; if (apiKey != null) url += $"&key={apiKey}"; var resp = await client.GetFromJsonAsync<SearchResponse>(url); return resp?.Results ?? Array.Empty<SearchResult>(); } var results = await Luisearch("linux kernel"); foreach (var r in results) Console.WriteLine($"{r.Title}\n {r.Url}\n");
// build.gradle: implementation("com.squareup.okhttp3:okhttp:4.12.0") // implementation("org.json:json:20240303") import okhttp3.OkHttpClient import okhttp3.Request import org.json.JSONObject import java.net.URLEncoder fun luisearch(query: String, apiKey: String? = null): List<Map<String, String>> { val encoded = URLEncoder.encode(query, "UTF-8") var url = "https://stevens-predictions-get-feet.trycloudflare.com/api/search?q=$encoded" if (apiKey != null) url += "&key=$apiKey" val client = OkHttpClient() val req = Request.Builder().url(url).build() val body = client.newCall(req).execute().use { it.body!!.string() } val data = JSONObject(body) val results = data.getJSONArray("results") return (0 until results.length()).map { i -> val r = results.getJSONObject(i) mapOf("title" to r.getString("title"), "url" to r.getString("url")) } } fun main() { luisearch("linux kernel").forEach { r -> println("${r["title"]}\n ${r["url"]}\n") } }

Embed Widget

Add a search box to your own site with a few lines of HTML. Live preview below:

<!-- Luisearch embed widget --> <div id="ls-widget"> <input id="ls-q" type="text" placeholder="Search..."> <button onclick="lsSearch()">Search</button> <div id="ls-results"></div> </div> <script> async function lsSearch() { const q = document.getElementById('ls-q').value; const res = await fetch('https://stevens-predictions-get-feet.trycloudflare.com/api/search?q=' + encodeURIComponent(q)); const { results } = await res.json(); document.getElementById('ls-results').innerHTML = results.map(r => `<div><a href="${r.url}" target="_blank">${r.title}</a><br>${r.snippet}</div>` ).join(''); } </script>

FAQ

Is Luisearch free to use?
Yes, fully free — no paywalls. There are real rate limits by tier though: 20 req/min with no key, 120 req/min with a free key, 300 req/min with an account (plus response caching), and unlimited on the Plus tier. See /tiers for the full breakdown. Luisearch is one product in the LuisHae family of real, multi-user services — not a one-person hobby project.
Do I need an API key?
No. The search endpoint works without any key. A key raises your rate limit and gives you attribution in the logs. If you pass an invalid key, you'll get a 401 — just don't pass a key at all if you don't have one.
How is the index built?
A custom Python crawler follows links recursively from a large seed list and keeps expanding outward. Every discovered page has its title and content extracted and stored in SQLite on an external drive. The index is continuously growing — check the live counters on the homepage or /api/info for the current page/site/image/video/download counts, since any number written here would go stale fast.
Can I request specific sites to be crawled?
Not yet. The crawler is manually seeded. If you want a site added, contact the admin.
What does BM25 mean?
BM25 (Best Match 25) is a probabilistic ranking algorithm used by Elasticsearch, Solr, and Lucene. It scores documents by how often your search terms appear, adjusted for how rare the terms are across the whole index. Luisearch's search() computes the real BM25 IDF and term-saturation formulas at query time (not a simplified stand-in), then applies a secondary boost/penalty pass over the top candidates.
Is the source code available?
Not yet publicly. The backend is a single Python file (several thousand lines at this point — it covers a lot more than just search now) with SQLite for storage and BM25 computed at query time. AI features (the answer box, LuisPaper, AI Chat) call DeepSeek's hosted API first, falling back to Groq if the DeepSeek key is unavailable — no local/Ollama inference is used.
How does the Images tab work?
As the crawler indexes pages, it extracts every <img> tag and stores the src, alt text, and source page URL in a separate images.db database. When you click the 🖼 Images tab and search, results are matched against the alt text. See the live count via /api/image-stats or on the homepage.
How does the Videos tab work?
A dedicated video crawler scrapes YouTube search results across 60+ topic queries (programming, science, math, education, etc.) and stores video metadata — title, thumbnail, duration, channel — in a separate videos.db. Searching the Videos tab matches against title and description. No videos are downloaded; links open YouTube directly.
What's in the Downloads tab?
A separate crawler indexes real downloadable files — Linux ISOs, Apple IPSW firmware, GGUF AI models, and common app installers — from official mirrors and archives (Ubuntu, Debian, Arch, Fedora, ipsw.me, Hugging Face, and more), storing title, category, version, size, and a direct download URL in downloads.db. It runs continuously, not as a one-time pass.
What is AI Chat?
A separate ChatGPT-style multi-turn chat at /ai/chat, with its own account system (distinct from Luisearch's own accounts and LuisPaper's). It's powered by DeepSeek and does not use web search grounding. You can attach an image — it's described by a real vision model (Groq's qwen/qwen3.6-27b) first, then that description is handed to DeepSeek so it can answer about the image naturally.
What is the Index Globe?
/map is a real, rotating globe (plain canvas, real Natural Earth coastline data, no external map library) showing the top indexed hosts geolocated by actual DNS + IP geolocation. You can also look up any domain live and drop a highlighted pin for it.
What is the Index Galaxy?
/galaxy renders the whole index as an explorable galaxy — every crawled page is a star, clustered into constellations by domain and colored by a hash of the hostname. Drag to pan, scroll/pinch to zoom, click a star to open the real page. It also polls the crawler's live status, so a light-burst pulses and a new star fades in every time a genuinely new page gets indexed — you're watching the index grow in real time.
What happens when a search result is dead?
Resurrection mode kicks in: when a result URL fails to load, the site does a real liveness check via /api/resurrect. If the site is confirmed dead but was previously crawled, you still get the archived title/content from the index instead of a dead end.
What is Nexus?
Nexus is a full multi-user chat platform in the LuisHae family — servers, channels, DMs, roles, polls, calls, and file/image sharing under real accounts. Realtime updates (messages, presence, typing, reactions) push over a genuine WebSocket connection (/api/nexus/ws) instead of polling, with an automatic long-poll fallback if a client's network blocks WebSocket upgrades.
Does Nexus support voice messages?
Yes — voice clips are transcribed automatically via a native faster-whisper service running directly on the host (no Docker, no external API call), currently on the medium model for better accuracy. The transcript comes back through /api/nexus/transcribe.
What is LuisPaper?
LuisPaper (at /ai) turns a topic or question into a structured, long-form AI research report — title, abstract, headed sections, conclusion, and a real numbered bibliography — grounded only in actual Luisearch search results, streamed in as it's generated. It's separate from the short inline AI answer box above regular search results.
What data does Luisearch store about my searches?
See /privacy for the full, honest breakdown — including what's currently a real gap (query logs have no expiry yet). No IP address is ever stored with a query, and there's no ad tracking or third-party analytics anywhere.
Luisearch API Get API Key · Search

Keyboard Shortcuts

Next section]
Previous section[
Clear docs searchEscape
Focus docs search/
Close this modalEscape