Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.sirius.menu/llms.txt

Use this file to discover all available pages before exploring further.

Follow these and your integration will be fast, cheap, and resilient — and you’ll almost never see a 429.

Cache everything

The single biggest win. Responses are served from Cloudflare’s edge and carry Cache-Control + ETag. You should layer your own cache on top.

Respect Cache-Control

Trending changes slowly (5 min), detail pages medium (1 min), lists fast (30 s). Don’t re-fetch inside those windows.

Use ETags

Store the ETag and send If-None-Match. A 304 is free — it doesn’t count against your rate limit.
const cache = new Map(); // url -> { etag, body }

async function getCached(url) {
  const prev = cache.get(url);
  const res = await fetch(url, prev ? { headers: { "If-None-Match": prev.etag } } : {});
  if (res.status === 304) return prev.body;
  const body = await res.json();
  cache.set(url, { etag: res.headers.get("etag"), body });
  return body;
}

Sync, don’t re-scrape

If you maintain a local copy of the catalogue, never re-page through everything on a schedule. Pull only what changed:
1

Do one full backfill

Page through GET /v1/scripts with sortBy=updatedAt&order=asc using cursor, storing each script and the max updatedAt you see.
2

Then sync deltas

On a timer, call GET /v1/scripts?updatedSince=<lastSeen>&sortBy=updatedAt&order=asc and upsert the results. Advance lastSeen to the new max updatedAt.
3

Resolve specifics in bulk

Need to refresh a known set (e.g. the scripts a user saved)? Use POST /v1/scripts/batch instead of one request per script.

Execute with loadstring

Every script returns a loadstring URL — a stable, separately-cached execution endpoint at script.roscripts.io. Use it directly rather than fetching raw source and reconstructing the loader:
loadstring(game:HttpGet(script.loadstring))()
Only call loadstring on scripts the user explicitly chose to run, and surface the script’s key and patched flags first. Never auto-execute search results.

Filter server-side

Push filters into the query instead of fetching broadly and filtering on the client — it’s faster, cheaper, and paginates correctly:
# Good — let the API do the work
curl "https://api.roscripts.io/v1/scripts?placeId=2753915549&key=0&verified=1&sortBy=views"
Combine mode, key, universal, verified, patched, placeId, game, tag, ui, owner, minViews, and hasThumbnail freely. See the list endpoint.

Trim payloads with fields

Only need a few fields for a list view? Ask for them:
curl "https://api.roscripts.io/v1/scripts?fields=id,title,slug,image,loadstring&max=50"
id is always included so you can correlate results.

Show quality signals

The catalogue carries trust signals — surface them so users make good choices:
FieldShow it as
verifiedA verified-creator badge
keyA “key system” warning before execution
patchedA “may be patched” flag
scriptType: "paid"A price/marketplace link (no raw source)
score, likeCount, viewsSort + social proof

Fail gracefully

Branch on error codes

Switch on the stable error.code, not the human message. See Errors.

Back off on 429/503

Honour Retry-After. Retry a handful of times with delay, then surface a friendly message.

Set a descriptive User-Agent

Identify your app (e.g. MyHub/2.1 (+https://myhub.example)). It helps us help you if something looks off, and keeps you clear of generic-bot heuristics.

Don’t

The catalogue isn’t real-time. Polling trending every second just burns your budget and serves you cached data anyway. Poll on the order of minutes.
The /raw endpoint is rate-limited harder and is for fetching the occasional script a user opened — not for mirroring source en masse.
Keys belong on a server. If you must call from a client, do it anonymously or proxy through your backend.
We add fields over time. Parse defensively, ignore unknown fields, and never index by position.