API reference
The Orihon reader SDK speaks to one delivery endpoint in your region. A client pulls the catalog for a library, then downloads the volumes it lists. Every route documented here lives on this host.
Base URL
Every call goes to the region you're assigned; this endpoint is ap-northeast-1.
https://orihon.dev/v1
Authenticate with a publisher key, passed as a bearer token. A key is tied to one publisher and one channel. Reader keys can browse the catalog and pull pages and volumes; they can't package or publish.
Authorization: Bearer orh_live_5b1e9a04c7f3d268
Endpoints
| Method | Path | Purpose |
|---|---|---|
| GET | /v1/catalog |
List the series and issues a library should show for a publisher and channel. |
| GET | /v1/volumes/:volume_id |
Download an immutable offline volume bundle. This is where the bytes are. |
| GET | /v1/pages/:issue_id |
List an issue's pages with their dimensions and checksums. |
| POST | /v1/entitlements/verify |
Confirm a reader may hold a title before the SDK caches it. |
| POST | /v1/reads/ack |
Record a reader's position so it follows them to another device. |
Read the catalog
The catalog decides what shows up in a reader's library. The SDK reads it at launch and whenever the app returns to the foreground — it's light, and it's the one response you want current.
GET /v1/catalog?series=srs_hoshikawa&channel=store
// 200 OK { "catalog_id": "cat_2026_07_11_9b2e", "channel": "store", "series": [ { "series_id": "srs_hoshikawa", "title": "Hoshikawa Lights", "volumes": [ { "volume_id": "vol_hoshikawa_07_3af19c", "number": 7, "page_count": 196, "size_bytes": 348127232 }, { "volume_id": "vol_hoshikawa_08_5c07b1", "number": 8, "page_count": 204, "size_bytes": 361824256 } ] } ] }
Download a volume
Every volume is addressed by its content hash and never changes — the same volume_id
gives back the same bytes forever. Clients hold onto them and only reach back when the catalog points to
something newer. Because the endpoint honours range requests, a transfer cut off in a tunnel picks up from
where it stopped instead of starting over.
GET /v1/volumes/vol_hoshikawa_07_3af19c Range: bytes=0-
// 200 OK (or 206 Partial Content) Content-Type: application/vnd.orihon.volume Content-Length: 348127232 ETag: "3af19c" Cache-Control: public, max-age=31536000, immutable
A single volume is 150–400 MB of packed full-resolution pages. A reader who loads a whole series before a trip pulls the entire run at once — several GB per device, paid once. Plan around libraries downloaded rather than page views: readers sync when they open the app, so a new release spreads across a day instead of arriving in a spike.
List an issue's pages
This returns an issue's pages with their dimensions and per-page checksums, so the SDK can confirm what it cached and re-pull a single bad page rather than the whole volume.
GET /v1/pages/iss_hoshikawa_c052
// 200 OK { "issue_id": "iss_hoshikawa_c052", "volume_id": "vol_hoshikawa_07_3af19c", "reading_direction": "rtl", "pages": [ { "index": 0, "w": 1536, "h": 2172, "sha256": "7d10…a4" }, { "index": 1, "w": 1536, "h": 2172, "sha256": "c98b…19" } ] }
Verify an entitlement
Called before the SDK caches a title, so a device only holds what the reader is allowed to keep. Bundles are signed as well, so a file lifted off a device is inert without a valid entitlement.
POST /v1/entitlements/verify Content-Type: application/json { "publisher": "pub_5b1e9a04", "reader_token": "rt_9f2c…", "volume_id": "vol_hoshikawa_07_3af19c" }
// 200 OK { "entitled": true, "scope": "owned", "expires": null }
Acknowledge a read position
Not required, but worth wiring up: it's what lets a reader set a volume down on their phone and open it on a tablet at the same page. It's the only call that sends anything upstream, and it's kept deliberately tiny.
POST /v1/reads/ack Content-Type: application/json { "reader_token": "rt_9f2c…", "issue_id": "iss_hoshikawa_c052", "page": 41 }
SDK quickstart
Swift, for iOS. The Android SDK mirrors these calls.
import Orihon let reader = try await Orihon.start( publisherId: "pub_5b1e9a04", endpoint: "https://orihon.dev", channel: "store" ) // Pre-cache a volume the reader owns; resumes on its own if the network drops. let volume = try await reader.library.download("vol_hoshikawa_07_3af19c") if volume.isReadyOffline { print("Cached \(volume.pageCount) pages") }
Errors
| Code | Meaning | What to do |
|---|---|---|
| 401 | Key missing, malformed, or revoked. | Confirm the key is current. Each key is scoped to one publisher and channel. |
| 403 | Reader is not entitled to this title. | Re-check entitlement; don't cache. The catalog lists only what a channel may show. |
| 404 | No such volume or issue for this publisher. | Usually a stale ID. Re-read the catalog; immutable IDs never change meaning. |
| 429 | Too many catalog resolves from one address. | Respect Retry-After; the SDK already backs off with jitter. |
Service health for this region is published at /status.