Glymonir HTTP API
Programmatic access to the Glymonir image gallery — browse / search / download the public gallery, manage your own libraries, and upload pictures. Wrapped by the official glymonir-cli, and usable directly over HTTP.
Base URL https://api.glymonir.com/api · local dev: http://localhost:8123/api
Quick start (CLI)
npm i -g glymonir-cli # or run any command with: npx glymonir-cli …
glymonir login --api-key gly_live_xxxxxxxx # store your key once
glymonir gallery search cat --limit 5 # preview matches
glymonir gallery download cat --variant original --meta --out ./out # pull images + metadata
glymonir upload ./*.jpg --library "Travel 2026" # upload to your libraryCreate a key in the web dashboard (Settings → API keys), login once, and every command reuses it.
Authentication
Send your API key as a Bearer token:
Authorization: Bearer gly_live_xxxxxxxxA key acts as the user who created it. Create or revoke keys in the dashboard (Settings → API keys), or via the key-management endpoints.
Scopes
A key carries one or more of three scopes — grant the least it needs:
| Scope | Allows |
|---|---|
read | Read / search / download the public gallery + your own libraries & collections |
write | Upload to and manage your own libraries (create / edit / organize) |
delete | Delete your own pictures / collections (reserved — not yet wired to an endpoint) |
The public gallery is read-only through the API — browse, search, and download it; your uploads go to your own libraries (below). Beyond scopes, your plan unlocks data depth: multilingual caption / concepts in picture metadata need a Pro subscription.
Rate limits
Per API key, set by the owner's plan. Image bytes (served from the CDN) are not counted — only API calls.
| Tier | Per minute (burst) | Per month |
|---|---|---|
| Free / Starter | 60 (120) | 50,000 |
| Pro | 300 (600) | 500,000 |
Over the limit → 42900 with a Retry-After header. The CLI self-paces automatically.
Response envelope
Every response is the same shape:
{ "code": 0, "data": { /* … */ }, "message": "ok" }code: 0 = success; any non-zero code is an error (table below). HTTP status mirrors the class (200 / 4xx / 5xx), but always check code.
Error codes
code | Meaning |
|---|---|
0 | OK |
40000 | Invalid request / parameter |
40100 | Not logged in (missing / wrong / expired key) |
40101 | Your key is missing the scope this endpoint requires |
40300 | Forbidden (user-level permission check) |
40400 | Not found (or not in the public gallery / not owned by you) |
42500 | Embedding not computed yet — retry in a few minutes |
42900 | Rate limit exceeded (carries Retry-After) |
50000 | Server error |
CLI commands
Install with npm i -g glymonir-cli (or prefix any command with npx). Auth resolves in order: --api-key flag → GLYMONIR_API_KEY env → saved login. Run glymonir <command> --help for the full flag list.
login / logout
glymonir login --api-key gly_live_… [--api-base https://api.glymonir.com/api]
glymonir logoutgallery search [query]
Preview matches (total count + first rows) without downloading.
glymonir gallery search cat --ratio landscape --limit 5
glymonir gallery search --color "#3a4f6b"Filters: --ratio <landscape|portrait|square|panoramic|tall | 16:9 | 1.78>, --color <hex>, --limit <n≤50>. Needs read.
gallery download [query]
Same filters, then downloads the image bytes to --out.
| Option | Meaning |
|---|---|
--variant <original|preview|thumbnail|all> | which size(s) — default original |
--meta | also write a <uploader>-<code>.json metadata sidecar |
--limit <n> · --resume · --concurrency <n> | cap count · skip files already on disk · parallel downloads |
Needs read. Downloads bump each picture's view + download count.
library / collection
glymonir library list
glymonir library create "Travel 2026"
glymonir library download "Travel 2026" --variant thumbnail --out ./lib
glymonir collection create "Travel 2026" "Japan"
glymonir collection download "Travel 2026" "Japan" --out ./japan<library> and <collection> accept a name or id (names are unique per user / per library). list / download need read; create needs write. Always own-only.
upload [files…]
glymonir upload ./*.jpg --library "Travel 2026" # into a library by name
glymonir upload ./photos/*.jpg --library 42 --resume # resumable batch into library 42Preprocesses locally (variants, palette, thumbhash) and uploads into your own library — pass --library <name|id> (needs write). Other flags: --name, --introduction, --tags, --manifest <jsonl>, --resume, --concurrency, --dry-run. --manifest takes one JSON object per line ({"file":"…","name":"…","tags":[…],"libraryId":"…"}) for per-file metadata. name is optional: without --name (and without a manifest name), the CLI does not derive one from the filename and the API stores picture.name = null.
HTTP API
Every endpoint takes Authorization: Bearer <key> and returns the envelope above. Pictures are addressed by their short base58 code (never the internal id).
Gallery (read)
Public gallery, review-approved pictures only. Anything else (missing / library-scoped / not yet approved) collapses to 40400.
| Endpoint | Purpose | Key params |
|---|---|---|
GET /gallery/pictures | Browse, newest first (cursor) | cursor, limit (≤200) |
GET /gallery/search | Keyword + filter search, with total | q, color (hex), minRatio / maxRatio, page / size |
GET /gallery/picture/{code} | One picture's full metadata | — |
POST /gallery/downloads | Record downloads (view + download +1) | body { "codes": ["…"] } |
Browse / search return "lite" items (code, name, dimensions, ratio, urls, …). The detail endpoint adds caption / concepts (filled only on a Pro account, otherwise empty):
{
"tier": "pro", "code": "upWAGbVRyd", "uploader": "alice",
"width": 4032, "height": 3024, "ratio": 1.333,
"format": "JPEG", "sizeBytes": "5242880",
"urls": { "original": "…", "preview": "…", "thumbnail": "…" },
"canonicalUrl": "…", "attribution": { "text": "…", "url": "…" },
"thumbhash": "…", "palette": [ … ], "exif": { … },
"name": "…", "introduction": "…", "tags": [ … ],
"caption": { "en": "…", "zh-cn": "…", "ja-jp": "…", "ko-kr": "…" },
"concepts": { "en": [ … ], "zh-cn": [ … ], "ja-jp": [ … ], "ko-kr": [ … ] }
}Your libraries (/me — own-only)
| Endpoint | Purpose |
|---|---|
GET /me/libraries · POST /me/libraries | list / create your libraries (POST body { "name": "…" }) |
GET /me/libraries/{id}/collections · POST …/collections | list / create collections |
GET /me/libraries/{id}/pictures | search your library (gallery filters + since / until) |
GET /me/collections/{id}/pictures | list a collection (page / size) |
List / create as above need read / write. Every endpoint is own-only — another user's library returns 40400.
Picture upload (write)
Easiest path: the upload CLI command. Limits on every upload: JPEG / PNG / WebP only, ≤ 50 MB. A violation returns 40000 naming the rule.
Raw HTTP (non-Node integrators) is a two-stage flow: POST /picture/upload/r2/check (dedup probe → presigned PUT URLs for the variants you don't already have) → PUT the bytes to those URLs → POST /picture/upload/r2/finalize (creates the row). The finalize body accepts optional name, introduction, and tags. Omit name (or send JSON null) to create a picture with no display name; filenames and hashes are never substituted by the API. The CLI's preprocess.ts is the reference for generating the variants.
API key management
Manage keys in the dashboard (Settings → API keys), or programmatically under /user/api-keys:
| Endpoint | Purpose |
|---|---|
POST /user/api-keys | create — body { "name": "…", "scopes": ["read"], "description"?, "expiresInDays"? }; response includes the plaintext key once |
GET /user/api-keys | list your keys (no plaintext) |
POST /user/api-keys/{id}/revoke | revoke a key |
GET /user/api-keys/available-scopes | the scopes you may grant |
Scopes are immutable once a key is issued — to change them, create a new key and revoke the old one. Key management uses your dashboard session, not an API key.
