Skip to content

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)

bash
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 library

Create 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_xxxxxxxx

A 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:

ScopeAllows
readRead / search / download the public gallery + your own libraries & collections
writeUpload to and manage your own libraries (create / edit / organize)
deleteDelete 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.

TierPer minute (burst)Per month
Free / Starter60 (120)50,000
Pro300 (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:

json
{ "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

codeMeaning
0OK
40000Invalid request / parameter
40100Not logged in (missing / wrong / expired key)
40101Your key is missing the scope this endpoint requires
40300Forbidden (user-level permission check)
40400Not found (or not in the public gallery / not owned by you)
42500Embedding not computed yet — retry in a few minutes
42900Rate limit exceeded (carries Retry-After)
50000Server 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

bash
glymonir login --api-key gly_live_… [--api-base https://api.glymonir.com/api]
glymonir logout

Preview matches (total count + first rows) without downloading.

bash
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.

Same filters, then downloads the image bytes to --out.

OptionMeaning
--variant <original|preview|thumbnail|all>which size(s) — default original
--metaalso 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

bash
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…]

bash
glymonir upload ./*.jpg --library "Travel 2026"       # into a library by name
glymonir upload ./photos/*.jpg --library 42 --resume  # resumable batch into library 42

Preprocesses 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).

Public gallery, review-approved pictures only. Anything else (missing / library-scoped / not yet approved) collapses to 40400.

EndpointPurposeKey params
GET /gallery/picturesBrowse, newest first (cursor)cursor, limit (≤200)
GET /gallery/searchKeyword + filter search, with totalq, color (hex), minRatio / maxRatio, page / size
GET /gallery/picture/{code}One picture's full metadata
POST /gallery/downloadsRecord 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):

json
{
  "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)

EndpointPurpose
GET /me/libraries · POST /me/librarieslist / create your libraries (POST body { "name": "…" })
GET /me/libraries/{id}/collections · POST …/collectionslist / create collections
GET /me/libraries/{id}/picturessearch your library (gallery filters + since / until)
GET /me/collections/{id}/pictureslist 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:

EndpointPurpose
POST /user/api-keyscreate — body { "name": "…", "scopes": ["read"], "description"?, "expiresInDays"? }; response includes the plaintext key once
GET /user/api-keyslist your keys (no plaintext)
POST /user/api-keys/{id}/revokerevoke a key
GET /user/api-keys/available-scopesthe 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.

Released under the MIT License.