Docs API conventions

API conventions

Cirrus uses consistent names and response envelopes so that response cardinality and operation-specific data are clear to clients.

Download OpenAPI specification

Response envelopes

Resource fields describe the cardinality of a successful response. Operation-specific output is kept separate from resource data.

FieldMeaning
itemOne resource.
items A collection of zero or more resources.
result Operation-specific data that is not a resource, such as an upload session.
context Request and authentication context returned by public routes.
nextToken An opaque continuation token on paginated collections.

Collection

{
  "items": [
    {
      "id": "pub_123"
    }
  ],
  "nextToken": null,
  "context": {
    "path": "/v1/publications",
    "method": "GET",
    "requestId": "req_123",
    "authentication": {
      "sub": "user_123",
      "scopeId": "scope_123"
    }
  }
}

Single resource

{
  "item": {
    "id": "pub_123"
  },
  "context": {
    "path": "/v1/publications/pub_123",
    "method": "GET",
    "requestId": "req_123",
    "authentication": {
      "sub": "user_123",
      "scopeId": "scope_123"
    }
  }
}

Resource and result

{
  "item": {
    "id": "pub_123"
  },
  "result": {
    "objectKey": "publications/pub_123/book.epub",
    "uploadUrl": "https://example.com/upload"
  },
  "context": {
    "path": "/v1/publications",
    "method": "POST",
    "requestId": "req_123",
    "authentication": {
      "sub": "user_123",
      "scopeId": "scope_123"
    }
  }
}

Some lookup routes allow no configured resource and return item: null. A missing resource on an ordinary ID lookup returns a 404. Check each endpoint schema for its exact nullability.

Names and values

JSON fields

Field names use camelCase. Boolean fields should read as predicates, such as isDefault or hasSecret.

Paths

Paths use lowercase plural resource names. Multi-word path segments use kebab-case, for example /v1/reader-instances.

Identifiers

Treat identifiers and continuation tokens as opaque strings. Do not derive meaning from their format or construct them in a client.

Dates and times

ISO timestamp fields use an Iso suffix, such as createdAtIso. Parse values as timestamps instead of displaying the raw value.

Field types

JSON types are significant and clients should not coerce fields based on their names or contents. In particular:

FieldJSON typeNotes
Edition.version numberNumeric edition version.
Edition.metadata.fileSize string Decimal byte count encoded as a string.
Edition.metadata.pageCount string Decimal page count encoded as a string.
ReaderInstance.configuration object Nested reader configuration containing layout regions, features, settings, fonts, and related state.
ReaderInstance.designerState object Nested state used to restore the reader designer.

Pagination

The endpoints below use cursor pagination. Send the response's nextToken unchanged as the nextToken query parameter in the next request. A null value means there are no more pages. Clients must not inspect, modify, or persist a token as a permanent cursor.

EndpointParametersDefault page size
GET /v1/publications limit, nextToken10
GET /v1/reader-instances limit, nextToken10

The limit parameter accepts an integer from 1 to 50. Other list endpoints are not currently paginated and return their complete result set.

GET /v1/publications?limit=10&nextToken=TOKEN_FROM_PREVIOUS_RESPONSE

Uploads and processing

Publication and asset creation return short-lived presigned S3 upload sessions. Upload each file with an HTTP PUT to uploadUrl, copying every entry in requiredHeaders exactly. The URL expires after the number of seconds in expiresIn.

Publications

POST /v1/publications and edition creation return the publication in item and one upload session in result. A separate optional result.cover session is returned when coverFilename is supplied. Publication uploads enter a quarantine prefix and are scanned before becoming available.

Assets

POST /v1/resources/assets returns one descriptor in result[] for each requested asset. Each descriptor contains its asset id, object key, upload URL, expiry, and required headers.

await fetch(uploadSession.uploadUrl, {
  method: 'PUT',
  headers: uploadSession.requiredHeaders,
  body: file
})

Publication upload statuses

StatusMeaningTerminal
upload_pending Waiting for upload, scanning, or processing. No
uploaded Upload received; downstream processing may still be running. No
available Scanning and processing completed successfully. Yes
upload_quarantine The upload was quarantined after a failed security scan. Yes
upload_failed Scanning or upload processing failed. Yes

Poll the publication or edition resource until uploadStatus reaches a terminal value. The create request must include the correct edition.type: EPUB, PDF, or Audio. LPF audiobook packages use Audio.

Errors

Error responses use error for a machine-readable code and message for a human-readable explanation. The request ID is context.requestId; it is not a top-level field. Use the HTTP status and error code for client control flow, and include the request ID when reporting an error. Do not match message text.

FieldTypeDescription
errorstringMachine-readable error code.
messagestringHuman-readable explanation.
context.pathstring Path that handled the request.
context.method stringHTTP request method.
context.requestId string Request identifier used for tracing and support.
context.authentication object Public authentication context when authentication completed.
detailsarray Field-level validation or operation details when available.
details[].message stringDescription of the issue.
details[].path (string | number)[] Path to the invalid field. Numbers identify array indexes.
details[].code string Machine-readable validation issue code.

details is present on validation error responses, including ZOD_ERROR. The path and code fields on an individual detail are optional. Errors raised before authentication completes can return a context without authentication.

{
  "error": "ZOD_ERROR",
  "message": "Invalid payload sent to API",
  "context": {
    "path": "/v1/publications",
    "method": "POST",
    "requestId": "req_123",
    "authentication": {
      "sub": "user_123",
      "scopeId": "scope_123"
    }
  },
  "details": [
    {
      "message": "Expected string, received number",
      "path": [
        "edition",
        "title"
      ],
      "code": "invalid_type"
    },
    {
      "message": "Expected string, received null",
      "path": [
        "collectionIds",
        0
      ],
      "code": "invalid_type"
    }
  ]
}