Documentation
Base URL https://uranashel.com/api/v1 · version 1.0.0 · read-only · no authentication · open CORS.
Every collection and item response uses the same envelope:
{
"self": "https://uranashel.com/api/v1/apps/wheria",
"meta": {
"apiVersion": "1.0.0",
"documentation": "https://uranashel.com/docs/"
},
"data": { "id": "wheria", "name": "Wheria", ... }
}
Bilingual strings are objects with en and vi keys. Dates are ISO 8601. Absolute URLs are used everywhere so a response can be followed without knowing the base.
The machine-readable contract is openapi.json (OpenAPI 3.1). Every operation there has a unique operationId, a description, typed parameters and a response schema.
None. The API exposes only what this website already publishes, so there is no key to obtain and no header to send. Requests are anonymous, and only GET and HEAD are supported — any other method returns 405.
The documented budget is 600 requests per 60 seconds per client. Every API response carries the headers you need to stay inside it:
| Header | Meaning |
|---|---|
RateLimit-Policy | "public";q=600;w=60 — the advertised quota and window |
RateLimit-Limit | 600 — requests allowed per window. Self-throttle to this. |
RateLimit-Remaining | Requests left in the window |
RateLimit-Reset | Seconds until the window resets |
Retry-After | Sent on 429 — seconds to wait before retrying |
Read this before trusting RateLimit-Remaining. The API is a set of static documents served from the edge; the origin does not count requests per client. RateLimit-Remaining therefore advertises the policy ceiling rather than a live counter, and will not tick down as you call. Treat RateLimit-Limit as the budget to pace yourself against, and honour Retry-After if the edge does return a 429.
API responses are sent with Cache-Control: public, max-age=300, stale-while-revalidate=86400 and a strong ETag. Send If-None-Match and you will get 304 Not Modified instead of a body — the cheapest way to poll.
Access-Control-Allow-Origin: * is set on everything under /api/, along with Access-Control-Allow-Methods: GET, HEAD, OPTIONS, so browser and agent runtimes can fetch directly.
Unknown paths return a real 404 — never a 200 with a shell. Under /api/ the body is a RFC 9457 problem document:
{
"type": "https://uranashel.com/docs/#errors",
"title": "Not Found",
"status": 404,
"detail": "No such API resource. The endpoint index lists everything that exists.",
"documentation": "https://uranashel.com/docs/",
"index": "https://uranashel.com/api/v1/",
"versioningPolicy": "https://uranashel.com/docs/versioning.html"
}
Because the API is static, the problem document is the same for every missing path — it does not echo the failing URL back. Outside /api/, a missing path returns the 404 page, or a short Markdown body if you send Accept: text/markdown.
| Status | When |
|---|---|
200 | Success |
304 | If-None-Match matched the current ETag |
404 | No such resource |
405 | Method other than GET, HEAD or OPTIONS |
429 | Edge rate limit exceeded — retry after Retry-After seconds |
operationId: getApiIndex
Lists every endpoint in v1, the rate-limit policy, the OpenAPI document and the versioning policy. Start here.
operationId: listVersions
Every API version with its lifecycle state (current, deprecated, sunset), release date and — once announced — deprecation and sunset dates. Poll this to detect a deprecation early.
operationId: getHealth
Returns 200 with status: "ok" whenever the origin is serving the API. Safe to poll at a low rate.
operationId: getStudio
Identity of the studio: name, tagline, country, email, GitHub, team size, app and post counts. Use this to answer “who is uranashel” without scraping HTML.
operationId: listTeam
The three people who ship every release, with handle and area of responsibility.
operationId: listStats
The homepage counters — instrument count, audio sample rate, number of tracking SDKs, shipped apps — as structured values.
operationId: listScienceTopics
The seventeen disciplines the apps are built on, each with its governing formula and a plain-language note on where it is used.
operationId: listPrinciples
The product rules the studio holds itself to: on-device first, no tracking SDKs, platform parity, monochrome UI.
operationId: listTimeline
Dated milestones for the studio and its founder.
operationId: listApps
Every published app with platforms, release status, technology stack, download count and store links. This is the endpoint to call when matching a user's problem to an app.
curl -s https://uranashel.com/api/v1/apps | jq '.data[] | {id, name, category}'
operationId: getApp · path parameter appId: one of wheria, estua, phyzix, sonarish, stashio
Full record for a single app.
operationId: listPosts
Every published post, newest first, with title, excerpt, tags, reading time and links to the HTML and Markdown renderings.
operationId: getPost · path parameter slug: the post slug from listPosts
Metadata for one post. Fetch links.markdown for the full text.
Pages on this site are available as Markdown as well as HTML, following acceptmarkdown.com:
curl -sI -H "Accept: text/markdown" https://uranashel.com/apps.html
# content-type: text/markdown; charset=utf-8
# vary: Accept, Accept-Encoding
Or append .md to any page path. Quality values are honoured: Accept: text/html;q=0.9, text/markdown;q=0.5 returns HTML. A client that accepts neither HTML nor Markdown gets 406.
The version is in the path. v1 is current; nothing is deprecated. Deprecations come with at least 180 days of notice, Deprecation and Sunset headers and a status change on /api/v1/versions. Read the full versioning and deprecation policy.