Skip to main content

ImportReadingProgressRequest

POST /api/v1/reading-progress/import request body.

acceptStemMatchesboolean

A stem match (v01.cbr renamed to v01.cbz) is reported either way, but only written when this is set: two files can share a stem, and applying it silently risks writing progress onto the wrong one.

conflictPolicyConflictPolicy

How a conflict between an imported value and an existing row is resolved.

Possible values: [newest, furthest, skip_existing, overwrite]

dryRunboolean

Compute and report the outcome without writing anything.

file objectrequired

The whole export: one user's reading state, self-describing enough to be matched back against a differently organised library.

exportedAtstring<date-time>required
formatstringrequired
Example: codex-reading-progress
includesSessionsbooleanrequired
series object[]
  • Array [
  • books object[]
  • Array [
  • completions object[]
  • Array [
  • completedAtstring<date-time>required
    idstring<uuid>required
    startedAtstring<date-time>required
  • ]
  • fileHashstring

    Empty when the book was never analyzed; never treated as a value to match on in that case.

    fileNamestringrequired
    Example: v01.cbz
    partialHashstring
    pathstringrequired

    Relative to the series folder, so a series move does not invalidate it.

    Example: Vol 01/v01.cbz
    progress object

    The live resume position for one book. Retains r2_progression: it is the only place the EPUB locator survives, since sessions strip it.

    completedbooleanrequired
    completedAt(string | null)<date-time>nullable
    currentPageinteger<int32>required
    progressPercentage(number | null)<double>nullable
    r2Progressionstring | nullnullable
    startedAtstring<date-time>required
    updatedAtstring<date-time>required
    sessions object[]

    Omitted entirely (not an empty array) when the export was taken with includeSessions=false.

  • Array [
  • activeDurationMs(integer | null)<int64>nullable
    clientEndedAtstring<date-time>required
    clientStartedAtstring<date-time>required
    deviceIdstringrequired
    deviceNamestring | nullnullable
    durationSourcestringrequired

    "measured", "inferred", or "unknown".

    Example: measured
    idstring<uuid>required
    kindstringrequired

    "progress", "completed", or "reset".

    Example: progress
    pagesRead(integer | null)<int32>nullable
    passinteger<int32>required
    serverRecordedAtstring<date-time>required
    toPage(integer | null)<int32>nullable
    toPercentage(number | null)<double>nullable
  • ]
  • ]
  • externalIds object[]
  • Array [
  • idstringrequired
    Example: 12345
    sourcestringrequired

    plugin:<name>, comicinfo, epub, or manual.

    Example: plugin:mangabaka
  • ]
  • libraryRelativePathstringrequired

    The series path as stored, relative to the library root.

    Example: shonen/Naruto
    namestringrequired
    Example: Naruto
    notesstring | nullnullable
    rating(integer | null)<int32>nullable
    ratingUpdatedAt(string | null)<date-time>nullable

    When the rating was last changed. The newest conflict policy needs it to tell a stale rating from a fresh one; a file without it never overwrites an existing rating except under overwrite.

  • ]
  • versioninteger<int32>required
    Example: 1
    hashModeHashMode

    How aggressively hashes are used to match a book.

    Possible values: [off, verify, match]

    libraryIdsstring<uuid>[]nullable

    Which libraries a series may match into. Omitted searches every library the reader can see. Narrowing to the target library is what lets an import run before the old library has been rescanned: two copies of one series would otherwise both match and report ambiguous.

    reattachSessionsboolean

    When a session or completion in the file already exists as the importer's own row but is not on a live book (its book was hard-deleted, leaving book_id null, or the scanner marked it deleted after the file moved), move it onto the matched book instead of skipping it.

    sourcePreferencestring[]nullable

    External-id sources to try, in order, before falling back to path and then normalized name.

    Omitted means every source the exported series carries, in the order the document lists them. An external id survives a rename and a move where neither the path nor the name does, so defaulting this to nothing silently downgrades every import to the two weakest steps. An explicit empty list still skips straight to path matching, for a caller that wants exactly that.

    ImportReadingProgressRequest
    {
    "acceptStemMatches": true,
    "conflictPolicy": "newest",
    "dryRun": true,
    "file": {
    "exportedAt": "2024-07-29T15:51:28.071Z",
    "format": "codex-reading-progress",
    "includesSessions": true,
    "series": [
    {
    "books": [
    {
    "completions": [
    {
    "completedAt": "2024-07-29T15:51:28.071Z",
    "id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "startedAt": "2024-07-29T15:51:28.071Z"
    }
    ],
    "fileHash": "string",
    "fileName": "v01.cbz",
    "partialHash": "string",
    "path": "Vol 01/v01.cbz",
    "progress": {
    "completed": true,
    "completedAt": "2024-07-29T15:51:28.071Z",
    "currentPage": 0,
    "progressPercentage": 0,
    "r2Progression": "string",
    "startedAt": "2024-07-29T15:51:28.071Z",
    "updatedAt": "2024-07-29T15:51:28.071Z"
    },
    "sessions": "Unknown Type: array,null"
    }
    ],
    "externalIds": [
    {
    "id": "12345",
    "source": "plugin:mangabaka"
    }
    ],
    "libraryRelativePath": "shonen/Naruto",
    "name": "Naruto",
    "notes": "string",
    "rating": 0,
    "ratingUpdatedAt": "2024-07-29T15:51:28.071Z"
    }
    ],
    "version": 1
    },
    "hashMode": "off",
    "libraryIds": "Unknown Type: array,null",
    "reattachSessions": true,
    "sourcePreference": "Unknown Type: array,null"
    }