The integration contract for external platforms that receive work published from Inkroost. Version 1.
Inkroost creators can publish a series or a single chapter directly to your platform. The creator authorizes the link between their Inkroost account and your platform once (OAuth2, below); after that, each publish is one HTTPS request from Inkroost to your ingest endpoint, carrying a JSON manifest and a ZIP package of the artwork.
To integrate, your platform implements three endpoints — an OAuth2 authorization page, an OAuth2 token endpoint, and an ingest endpoint — and registers our callback URL. No code is deployed on the Inkroost side per partner: an administrator enters your three endpoint URLs and OAuth client credentials, and creators can start publishing to you.
Inkroost is a standard OAuth2 client using the authorization-code grant.
You issue us a client_id and client_secret for your platform.
response_type=code, client_id, redirect_uri,
state, and optionally scope.
code and the unchanged state:
https://inkroost.com/integrations/callback
state
are rejected.
grant_type=authorization_code with the
code, redirect_uri, client_id and
client_secret (form-encoded) to your token URL, and expect a JSON response with
access_token, and optionally refresh_token and
expires_in (seconds).
refresh_token was
issued, we POST grant_type=refresh_token to the same token URL before publishing.
Tokens are stored encrypted at rest, per creator and per platform, and are never written to logs.
Each publish is one POST to the ingest URL you provide, authenticated with the
creator's OAuth2 access token as a bearer token:
POST /your/ingest/endpoint HTTP/1.1 Authorization: Bearer <creator access token> Content-Type: multipart/form-data manifest = <JSON string, the manifest described in section 5> package = <ZIP file, the package described in section 4>
Respond with:
id (your identifier for
the received work) and url (a public link to it). If url is present, the
creator is shown a "View on platform" link.
error,
error_description or message in a JSON body and the creator sees a
shortened version of it. The publish is not retried.
Uploads can be large (see limits, section 6) — accept streamed multipart bodies and allow several minutes for a full-series publish.
package is a ZIP archive. Entry names are chosen so a plain lexical sort reproduces
reading order:
manifest.json — the same JSON as the manifest form field cover.png | cover.jpg | cover.webp — series cover artwork, when one exists chapter-001/page-001.png — page artwork, zero-padded, in reading order chapter-001/page-002.png chapter-010-5/page-001.png — fractional chapter numbers (10.5) use a dash
reading_mode in the manifest (paged or vertical) says which
presentation the creator designed for.chapters[].folder
values), never file timestamps.pages_missing; the numbering of the remaining entries stays gapless.
The manifest form field and the manifest.json archive entry are the same
JSON document:
{
"generator": "Inkroost",
"manifest_version": 1,
"published_at": "2026-08-30T12:00:00+00:00",
"scope": "series", // or "chapter"
"series": {
"title": "…",
"slug": "…",
"synopsis": "…",
"reading_direction": "ltr", // "ltr" or "rtl" (manga)
"reading_mode": "paged", // "paged" or "vertical" (webtoon)
"maturity_rating": "all_ages", // "all_ages", "teen" or "mature"
"genres": ["Fantasy", "Action"],
"content_origin": "…", // how the artwork was made, e.g. AI-assisted or hand-drawn
"cover": "cover.png", // archive entry name, or null
"source_url": "https://…" // canonical URL on Inkroost, or null
},
"creator": {
"name": "…", // the creator's public name — attribute the work to it
"profile_url": "https://…" // or null
},
"chapters": [
{
"number": 1,
"title": "…",
"folder": "chapter-001", // where this chapter's pages live in the ZIP
"page_count": 24, // pages actually in the ZIP
"pages_missing": 0,
"published": true, // false = still a draft on Inkroost
"access_mode": "free", // or "supporter_only"
"source_url": "https://…"
}
],
"chapter_count": 1,
"page_count": 24,
"pages_missing": 0
}
Fields may be added in future versions; unknown fields must be ignored. A breaking change increments
manifest_version.
"published": false or "access_mode": "supporter_only" are
included because the owner chose to send them — honor the flags when deciding what to show
publicly on your side.Implement the three endpoints, then send your authorization URL, token URL, ingest URL, scopes (if any) and OAuth client credentials to [email protected]. We register the integration and it appears on every creator's Integrations page.