Developers

Marking a book as read is an API operation.

When you mark a work as “Read” in your library, the website sends the request below. Your code can send the same request, get the same result, and pass the same checks.

Writes

A write request, line by line

PUT /v1/works/{id}/reader-status
Authorization: Bearer …
Idempotency-Key: 7f3c2a9e-read
Content-Type: application/json

{
  "actingSubject":
    "https://rezics.com/id/…",
  "expectedVersion": 3,
  "status": "read",
  "finishedOn": "2026-10-19"
}
The version, date, and idempotency key are examples.
  • The path identifies a work

    {id}

    Every item in REZICS has a permanent identifier beginning with https://rezics.com/id/. It stays the same across languages and sites.

  • State the identity

    actingSubject

    An account can act for itself or an organization. Every write states whose identity is acting, and the server checks its permissions before it runs.

  • Make retries safe

    Idempotency-Key

    Every write includes an idempotency key. After a timeout or disconnect, retry with the same key to avoid writing twice.

  • Prevent overwrites

    expectedVersion

    If you read version 3, state version 3 in your request. If someone else edits it first, your write will not overwrite their changes.

  • Errors use problem details

    application/problem+json

    Failures return a fixed code. Your code can branch on it without comparing message text.

Retries

Retry the same request and get the same result.

Send the same content again with the same key, and the server returns the first result: version stays at 4 and replayed becomes true. Reuse the key with different content and it returns 409 reader_status_conflict. If the version is no longer 3, it returns 409 stale_reader_status. Read again before writing.

  • First request

    200
    {
      "status": "read",
      "version": 4,
      "replayed": false
    }
  • Retry

    200
    {
      "status": "read",
      "version": 4,
      "replayed": true
    }
  • Stale version

    409
    {
      "status": 409,
      "code":
        "stale_reader_status"
    }

Types

The API and its types share one definition

The REZICS website calls the API with TypeScript. Request and response types come directly from the server’s route declarations. If a field is renamed or an error code is added, callers know at compile time. The TypeScript SDK comes from the same definition, so its types match the website’s.

OpenAPI 3.1 documentation comes from the same route declarations. It specifies each operation’s authentication, request format, and response for every status code.

main().v1
  .works({ id: uuid(work) })
  ['reader-status'].put({
    actingSubject,
    expectedVersion,
    status: 'read',
    ...dates,
  }, headers())
Excerpt from the REZICS library.

generated/openapi/main/public.json

Reads

Reads have rules too

  • nextCursor · snapshot

    Long lists include a cursor for the next page so you can read to the end. Library exports also include a snapshot. If data changes midway, the response says so instead of giving you a file assembled from mixed versions.

  • count.precision

    Search results say whether the total is exact or “at least” the stated number.

  • title.language · basis

    Titles include a language tag and writing direction, and explain whether the language was requested, matches the same script, uses another script, or is a fallback.

  • 404 resource_unavailable

    A resource you cannot access returns the same response as one that does not exist, so its existence stays private.

Build your tools on one API.

Use your own code to read and write works, library entries, and community data. Every operation follows REZICS identity and authorization rules.