Download OpenAPI specification:
API documentation for the Hebban.nl project.
See the changelog for the full API history.
Every API request must include:
Accept: application/json — Without this header, you'll receive 406 Not Acceptable.X-API-TOKEN: <your-token> — All endpoints require a valid API token (see Authentication below).The API uses two authentication schemes:
X-API-TOKEN header) — Required for all requests. Identifies your application./me/*). Obtained via /auth/login or /auth/register.Token lifecycle:
/auth/logout./auth/refresh to extend token lifetime if needed (rarely necessary).Common pitfalls:
X-API-TOKEN header → 401 Unauthenticated/me/* endpoints → 401 Unauthenticated/auth/logout when user signs out → Tokens remain validTrack requests across logs and errors using the X-Request-Id header:
400 Bad Request.X-Request-Id in the header.X-Request-Id header and the request_id field in the JSON body.All errors follow the RFC 9457 Problem Details format with Content-Type: application/problem+json:
{
"title": "Unauthenticated",
"status": 401,
"request_id": "01JCEXAMPLE123456789ABCDEF",
"code": "auth.unauthenticated"
}
The code member is the stable, machine-readable identifier clients should switch on. title and
detail are English framework defaults, sent to ease debugging. Do not show them to end users; map
code to your own copy instead.
Every code the API can return is listed below. The code property of the Error schema is an enum of
exactly this list, so a response carrying an undocumented code fails contract validation.
| Status | Code | When |
|---|---|---|
| 400 | pagination.invalid_cursor |
The cursor query parameter could not be decoded |
| 400 | validation.invalid_request_id |
X-Request-Id was sent but is not a valid ULID |
| 401 | auth.unauthenticated |
Missing or invalid X-API-TOKEN header, or missing or invalid bearer token on a user endpoint |
| 403 | auth.forbidden |
Authenticated, but not allowed to perform this action |
| 403 | auth.email_not_verified |
The account's email address is not verified. Returned by write operations that contribute content: ratings, reading statuses, read entries, reviews, comments, likes, lists, adding or removing a book from a challenge, follows, campaign submissions. Login, every GET request, account set-up (profile, avatar, joining a challenge, setting a pledge), and account-lifecycle operations (logout, refresh, preferences, notifications, mutes, account deletion) stay available. Changing the email address with a code (/me/email/*) requires a verified address |
| 403 | auth.invalid_signature |
Signed URL carries an invalid or expired signature |
| 404 | http.not_found |
Route or resource does not exist |
| 404 | auth.user_not_found |
POST /auth/firebase/token only: the Firebase token is valid, but no account belongs to that identity and registering it would succeed — send the user to POST /auth/firebase/register. A token registration would refuse in turn (an address another account already holds, Firebase email/password sign-in, or no email address at all) answers 401 instead |
| 406 | http.not_acceptable |
Missing Accept: application/json header |
| 409 | auth.account_exists |
Email address was taken between code verification and registration completion, or between requesting and confirming an email change |
| 409 | campaign.closed |
Campaign has ended and no longer accepts submissions |
| 409 | challenge.join.conflict |
Already joined this challenge |
| 409 | challenge.read_only |
Challenge is read-only |
| 409 | rating.delete.conflict |
Rating cannot be deleted while a review exists |
| 409 | review.create.conflict |
A review for this work already exists |
| 422 | validation.failed |
Request failed validation; see errors for the fields |
| 429 | rate_limit.exceeded |
Rate limit exceeded; wait for Retry-After seconds |
| 500 | server.error |
Unexpected server error; report the request_id |
On 422, each entry under errors carries its own code of the form validation.<rule>, named after
the validation rule that failed (for example validation.email, validation.required, validation.max).
Errors raised outside a validation rule carry validation.unknown. That per-field list is open and is
not part of the enum above.
All API endpoints are rate limited. Limits are applied per consumer and are indicated via response headers:
X-RateLimit-Limit — Maximum requests allowed in the current windowX-RateLimit-Remaining — Requests remaining in the current windowThree tiers apply:
/*/search endpoints have a stricter limit (default: 30 requests/minute)/me/collections, /me/activity, /me/app-sync (default: 20 requests/minute)When a limit is exceeded, the API returns 429 Too Many Requests with a Retry-After header.
List endpoints support pagination via query parameters:
page — Page number (default: 1)per_page — Items per page (default: 15, max: 250)Some endpoints use cursor-based pagination (e.g., /me/notifications) with a before timestamp parameter.
Some endpoints are idempotent and safe to retry:
204 No Content even if the resource was already deleted.204 No Content if the work is already present.This prevents errors when retrying failed requests or handling network issues.
POST /me/email/start mails a one-time code to the new address (POST /me/email/resend-code sends a
fresh one); POST /me/email/verify-code confirms it, after which the new address is on the account and
verified. An account with a password (has_password in the profile) sends its current password with
start. start and resend-code answer 202 whether or not the new address belongs to another
account or is reserved (see below); such an address receives no mail, so tell a user who gets no code
to check the address.
After a change the previous address may receive a notice with an undo link. POST /auth/email/revert
takes the token from that link: it restores the previous address, signs the account out everywhere,
removes its password and social sign-ins, and mails a password reset to the restored address. While the
link is valid (72 hours by default) the previous address counts as in use everywhere, including for the
account itself. email on PATCH /me is deprecated and will be removed once the site and app use the
code flow.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| email required | string <email> |
| password required | string <password> |
{- "email": "user@example.com",
- "password": "pa$$word"
}{- "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
- "token_type": "Bearer",
- "expires_in": 315360000,
- "user": {
- "id": 0,
- "name": "string",
- "slug": "string",
- "email": "string",
- "user_label": "normal",
- "avatar": { },
- "email_verified_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Creates an account that still has to confirm its address. An address
that is in use or reserved (see "Changing the email address" in the
introduction) returns 422 on email.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| name required | string |
| email required | string <email> |
| password required | string <password> |
| password_confirmation required | string <password> |
{- "name": "string",
- "email": "user@example.com",
- "password": "pa$$word",
- "password_confirmation": "pa$$word"
}{- "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
- "token_type": "Bearer",
- "expires_in": 315360000,
- "user": {
- "id": 0,
- "name": "string",
- "slug": "string",
- "email": "string",
- "user_label": "normal",
- "avatar": { },
- "email_verified_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Begins the in-app registration flow by sending a one-time verification code to the email address. The response is identical whether the address is new or already registered (anti-enumeration); an already-registered address instead receives a "you already have an account" email with a password-reset link. A reserved address (see "Changing the email address" in the introduction) gets the same response and no mail. No account is created at this step.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| email required | string <email> <= 255 characters |
{- "email": "user@example.com"
}{- "message": "string"
}Re-sends a fresh verification code, invalidating any previous one. The response is identical regardless of whether the address is already registered (anti-enumeration).
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| email required | string <email> <= 255 characters |
{- "email": "user@example.com"
}{- "message": "string"
}Verifies the one-time code. On success returns a short-lived, single-use proof bound to the email, to be submitted at the completion step. The code is limited-use and locks out after too many incorrect attempts.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| email required | string <email> <= 255 characters |
| code required | string The one-time verification code sent to the email address. |
{- "email": "user@example.com",
- "code": "string"
}{- "proof": "string",
- "expires_at": "2030-01-01T00:00:00+00:00"
}Validates any subset of the registration fields against the exact rules
applied at completion, for live per-field feedback. Stores nothing.
A lone password is checked for strength only; send password_confirmation
alongside it to also check that the two match.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| password | string <password> |
| password_confirmation | string <password> |
| name | string <= 255 characters |
| birthdate | string <date> |
{- "password": "pa$$word",
- "password_confirmation": "pa$$word",
- "name": "string",
- "birthdate": "2019-08-24"
}{- "valid": true,
- "fields": [
- "password",
- "name"
]
}Creates a complete, already-verified account in one step from the proof returned by verify-code. The email is taken from the proof, not the request body. Returns a JWT, like login; no verification-link email is sent. If the email was registered or reserved in the meantime (see "Changing the email address" in the introduction), returns 409.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| proof required | string The short-lived confirmation proof returned by verify-code. The email is derived from it. |
| password required | string <password> |
| password_confirmation required | string <password> |
| name required | string <= 255 characters |
| birthdate | string <date> |
| terms required | boolean Acceptance of the terms and conditions. Must be true. Value: true |
{- "proof": "string",
- "password": "pa$$word",
- "password_confirmation": "pa$$word",
- "name": "string",
- "birthdate": "2019-08-24",
- "terms": true
}{- "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
- "token_type": "Bearer",
- "expires_in": 315360000,
- "user": {
- "id": 0,
- "name": "string",
- "slug": "string",
- "email": "string",
- "user_label": "normal",
- "avatar": { },
- "email_verified_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Requests a password reset link for an email address.
This endpoint never reveals whether an account exists. A registered
address, an unknown address, and an address that already requested a link
moments ago all return the exact same 200 response. Only the submitted
value is validated: a missing or syntactically invalid email still returns
422.
Consequences for clients:
200 as confirmation that an account was found.The endpoint is rate limited per email address, per IP, and by an overall
ceiling; exceeding any of these returns 429.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| email required | string <email> |
{- "email": "user@example.com"
}{- "status": "We have emailed your password reset link."
}Validates a password reset token without consuming it. Use this before showing the reset form to provide immediate feedback if the link has expired or is invalid.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| email required | string <email> |
| token required | string |
{- "email": "user@example.com",
- "token": "string"
}{- "valid": true
}| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| email required | string <email> |
| token required | string |
| password required | string <password> |
| password_confirmation required | string <password> |
{- "email": "user@example.com",
- "token": "string",
- "password": "pa$$word",
- "password_confirmation": "pa$$word"
}{- "message": "string"
}Verifies a user's email address using a signed URL. No authentication required - the signed URL itself is proof of email ownership.
| id required | integer |
| hash required | string |
| expires required | integer URL expiration timestamp |
| signature required | string Cryptographic signature for URL validation |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "message": "string"
}Undoes an email change with the token from the undo notice; see
"Changing the email address" in the introduction for what a revert does.
No bearer token is needed, and one sent along is ignored. An invalid,
expired or already used token returns 422 on token. If the previous
address was taken by another account in the meantime, the response is
409 auth.account_exists and nothing changes. The endpoint has its own
rate limit per client address instead of the shared per-application one.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| token required | string The revert token from the link in the notice sent to the previous address. |
{- "token": "string"
}{- "message": "string"
}Request a new email verification link. The X-API-TOKEN header is always
required. email in the body is required unless the request carries a bearer
token, in which case the token's user is used; when both are present, the
body's email wins. The response is identical whether or not the address
exists or is already verified, to prevent email enumeration.
Rate limited per email address and per IP address.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
string <email> <= 255 characters |
{- "email": "user@example.com"
}{- "message": "If your email is registered and unverified, a verification link has been sent."
}| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
- "token_type": "Bearer",
- "expires_in": 315360000,
- "user": {
- "id": 0,
- "name": "string",
- "slug": "string",
- "email": "string",
- "user_label": "normal",
- "avatar": { },
- "email_verified_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Returns the authenticated user's own profile with private fields.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 88,
- "slug": "marty-mcfly",
- "name": "Marty McFly",
- "email": "marty@hillvalleymusic.com",
- "email_verified_at": "1955-11-12T06:00:00+00:00",
- "has_password": true,
- "user_label": "normal",
- "last_activity_at": "1985-10-26T08:18:00+00:00",
- "biography": "If you put your mind to it, you can accomplish anything.",
- "profile_visibility": "public",
- "birthdate": "1968-06-12",
- "gender": "male",
- "followers_count": 256,
- "following_count": 42,
- "reviews_count": 75,
- "challenges_count": 3,
- "reading_status_want_to_read_count": 34,
- "reading_status_read_count": 128,
- "reading_status_reading_count": 5,
- "created_at": "1955-11-12T06:00:00+00:00",
- "updated_at": "1985-10-26T08:18:00+00:00",
- "preferences": {
- "ui": {
- "theme": "retro",
- "sidebar_collapsed": false
}, - "profile": {
- "show_birthdate": true,
- "show_gender": true
}, - "notifications": {
- "comment.on.review": true,
- "follow": true
}
}
}
}Partially update the authenticated user's profile (PATCH semantics). Only provided fields will be updated.
Changing email here is deprecated; see "Changing the email address" in
the introduction. Until the field is removed, a change here clears
email_verified_at and sends a verification mail to the new address, so
operations that contribute content return 403 auth.email_not_verified
until it is confirmed; the previous address may receive an undo notice.
An address that is in use or reserved, or the one the account can be
restored to through an undo link, returns 422 on email.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| name | string <= 255 characters User's display name |
string <email> <= 255 characters Deprecated User's email address (must be unique). Deprecated: change the address with
| |
| password | string <password> >= 8 characters New password (requires password_confirmation) |
| password_confirmation | string <password> >= 8 characters Password confirmation (required when password is provided) |
null or Gender (string) User's gender preference | |
null or string <= 15000 characters User's biography or about text | |
null or string User's birthdate in YYYY-MM-DD format (cannot be in the future) | |
| profile_visibility | string (ProfileVisibility) Enum: "public" "protected" "private" User's profile visibility setting. Protected = visible to authenticated users. |
{- "name": "Jane Doe",
- "email": "jane@example.com",
- "password": "new-secure-password",
- "password_confirmation": "new-secure-password",
- "gender": { },
- "biography": "I love reading books about history and science fiction.",
- "birthdate": "1990-05-15",
- "profile_visibility": "public"
}{- "data": {
- "id": 0,
- "slug": "string",
- "name": "string",
- "user_label": "normal",
- "email": "user@example.com",
- "email_verified_at": { },
- "has_password": true,
- "avatar": { },
- "biography": { },
- "birthdate": { },
- "gender": { },
- "profile_visibility": "public",
- "followers_count": 0,
- "following_count": 0,
- "reviews_count": 0,
- "challenges_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "last_activity_at": "2019-08-24T14:15:22Z",
- "preferences": {
- "ui": {
- "theme": "dark",
- "sidebar_collapsed": false
}, - "profile": {
- "show_birthdate": false,
- "show_gender": false
}, - "notifications": {
- "comment.on.review": true,
- "follow": false,
- "like.on.comment": true
}
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Permanently deletes the authenticated user's account. The account is locked out immediately; data cleanup happens asynchronously.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Mails a one-time code to the new address. See "Changing the email address"
in the introduction. The account's current address, and the address it
can be restored to through an undo link, return 422 on email; a
missing or wrong password returns 422 on password. Requires a
verified address (403 auth.email_not_verified otherwise); not available
during impersonation (403 auth.forbidden).
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| email required | string <email> <= 255 characters The new email address. Must differ from the account's current address. |
| password | string <password> The account's current password. Required when the profile's |
{- "email": "user@example.com",
- "password": "pa$$word"
}{- "message": "string"
}Sends a fresh code to the address of the pending change, replacing the
previous one. For any other address, or when no change is pending,
nothing is sent and the response is the same 202. Same 403 and 422
cases as start, except that no password is needed.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| email required | string <email> <= 255 characters The new email address to send a fresh code to. |
{- "email": "user@example.com"
}{- "message": "string"
}Confirms the code. On success the new address replaces the current one,
verified, and the updated profile is returned; the previous address may
receive an undo notice (see the introduction). Same 403 cases, and the
same 422 cases on email, as start. A wrong, expired or used code, or
too many wrong attempts, returns 422 on code; a new code does not lift
the block. If the new address was taken or reserved by another account
in the meantime, the response is 409 auth.account_exists. In every
failure the account keeps its current address.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| email required | string <email> <= 255 characters The new email address the code was sent to. |
| code required | string <= 32 characters The one-time code sent to the new address. |
{- "email": "user@example.com",
- "code": "string"
}{- "data": {
- "id": 0,
- "slug": "string",
- "name": "string",
- "user_label": "normal",
- "email": "user@example.com",
- "email_verified_at": { },
- "has_password": true,
- "avatar": { },
- "biography": { },
- "birthdate": { },
- "gender": { },
- "profile_visibility": "public",
- "followers_count": 0,
- "following_count": 0,
- "reviews_count": 0,
- "challenges_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "last_activity_at": "2019-08-24T14:15:22Z",
- "preferences": {
- "ui": {
- "theme": "dark",
- "sidebar_collapsed": false
}, - "profile": {
- "show_birthdate": false,
- "show_gender": false
}, - "notifications": {
- "comment.on.review": true,
- "follow": false,
- "like.on.comment": true
}
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Upload a new avatar image for the authenticated user. If an avatar already exists, it will be replaced and the old file deleted.
Important: This endpoint requires multipart/form-data content type. Sending the file as a JSON string or base64-encoded body will be rejected.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| avatar required | string <binary> Avatar image file (JPEG, PNG, or WebP, max 2048 KB / 2 MB) |
{- "data": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}
}Remove the current user's avatar image
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}
}Update user preferences for the authenticated user. Supports 'ui' and 'notifications' namespaces. Values are merged with existing preferences (not replaced).
You can update one or both namespaces in a single request.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
object <= 50 properties Client-side UI preferences. No key validation - clients can store any valid JSON structure (max 50 keys). | |
object Profile visibility preferences. Only | |
object Notification preferences. All properties are optional boolean values for each NotificationType. |
{- "ui": {
- "theme": "dark",
- "sidebar_collapsed": false
}, - "profile": {
- "show_birthdate": true,
- "show_gender": true
}, - "notifications": {
- "comment.on.review": false,
- "comment.on.comment": true,
- "like.on.review": true,
- "like.on.comment": false,
- "like.on.book_list": true,
- "follow": true,
- "followed_user.reviews": false,
- "followed_user.rates": true,
- "followed_user.reading_status": false
}
}{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "email_verified_at": { },
- "name": "string",
- "avatar": { },
- "last_activity_at": "2019-08-24T14:15:22Z",
- "unread_notifications_count": 0
}
}| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "read": [
- 101,
- 102
], - "reading": [ ],
- "to_read": [
- 203
], - "reviewed": [
- [
- 203,
- 5011
]
], - "favorites": [
- 101,
- 203,
- 304
], - "rating": [
- [
- 101,
- 4
], - [
- 203,
- 5
]
], - "campaign_submitted": [ ],
- "like": {
- "article": [
- 123,
- 1212
], - "review": [
- 456
], - "booklist": [
- 789,
- 7878
], - "comment": [
- 1011
], - "event": [
- 1212,
- 1211
]
}, - "follow": {
- "author": [ ],
- "user": [ ]
}
}
}Returns user activity data with timestamps for app synchronization.
Unlike /me/activity, this endpoint includes timestamps on all fields,
making it suitable for syncing user state after login.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "read": [
- {
- "work_id": 101,
- "last_read": "2024-03-15",
- "updated_at": "2024-03-15T10:30:00+00:00"
}, - {
- "work_id": 102,
- "last_read": "2024-01-20",
- "updated_at": "2024-01-20T14:00:00+00:00"
}
], - "reading": [
- {
- "work_id": 203,
- "created_at": "2024-03-10T09:15:00+00:00"
}
], - "to_read": [
- {
- "work_id": 304,
- "created_at": "2024-02-01T11:00:00+00:00"
}
], - "favorites": [
- {
- "work_id": 101,
- "created_at": "2024-01-15T08:30:00+00:00"
}
], - "owned": [
- {
- "work_id": 102,
- "created_at": "2024-01-18T09:45:00+00:00"
}
], - "rating": [
- {
- "work_id": 101,
- "stars": 4,
- "created_at": "2024-03-16T12:00:00+00:00"
}
], - "reviewed": [
- {
- "work_id": 101,
- "review_id": 5011,
- "created_at": "2024-03-17T15:30:00+00:00"
}
]
}
}Returns a paginated list of the authenticated user's notifications. Supports filtering by read status and cursor-based pagination.
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| unread | integer Enum: 0 1 Filter to only unread notifications. Use |
| before | string <date-time> Return notifications created before this timestamp (RFC 3339 format) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": "497f6eca-6276-4993-bfeb-53cbbbba6f08",
- "type": "comment.on.review",
- "data": {
- "v": 1,
- "type": "like.on.review",
- "actor": {
- "id": 0,
- "name": "string",
- "slug": "string",
- "avatar": { }
}, - "subject": {
- "type": "review",
- "id": 0
}, - "context": {
- "parent": {
- "type": "review",
- "review": {
- "id": 0,
- "slug": "string",
- "title": "string",
- "stars": 1,
- "description": "string"
}, - "work": {
- "id": 0,
- "slug": "string",
- "title": "string",
- "cover_url": { },
- "description": { },
- "authors": [
- {
- "id": 0,
- "name": "string",
- "slug": "string"
}
]
}
}
}, - "meta": { }
}, - "read_at": { },
- "created_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Marks multiple notifications as read for the authenticated user. Can mark specific notifications by ID or all notifications (optionally filtered to unread only).
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| all required | boolean Mark all notifications as read |
| unread_only | boolean When 'all' is true, only mark unread notifications |
{- "ids": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Deletes multiple notifications by ID for the authenticated user.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| ids required | Array of strings <uuid> non-empty [ items <uuid > ] Notification IDs to delete |
{- "ids": [
- "497f6eca-6276-4993-bfeb-53cbbbba6f08"
]
}{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Idempotently marks a specific notification as read for the authenticated user. Returns 204 even if the notification doesn't exist, doesn't belong to the user, or is already read.
| id required | string <uuid> Notification ID (UUID) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Idempotently deletes a specific notification for the authenticated user. Returns 204 even if the notification doesn't exist or doesn't belong to the user.
| id required | string <uuid> Notification ID (UUID) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Returns the count of unread notifications for the authenticated user.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "count": 0
}Returns all notification mutes for the authenticated user.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "subject_type": "book_list",
- "subject_id": 0,
- "type": { },
- "until": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Creates or updates a notification mute for the authenticated user. If a mute already exists for the same subject_type, subject_id, and type combination, it will be updated.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| subject_type required | string Enum: "book_list" "campaign" "comment" "review" Type of the subject to mute |
| subject_id required | integer ID of the subject to mute |
null or string Specific notification type to mute (null to mute all types for this subject) | |
null or string When the mute should expire (null for indefinite, RFC 3339 format) |
{- "subject_type": "book_list",
- "subject_id": 0,
- "type": { },
- "until": { }
}{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Deletes a notification mute for the authenticated user. Idempotent - returns 204 even if the mute doesn't exist.
| id required | integer The ID of the notification mute to delete |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Lists users and contributors (authors) the authenticated user follows.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "authors": [
- {
- "id": 456,
- "name": "J.K. Rowling",
- "slug": "jk-rowling",
- "portrait_url": { },
- "portrait_alt_text": { },
- "portrait_attribution": { },
- "followed_at": "2025-01-15T10:30:00+00:00"
}
], - "users": [
- {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00",
- "followed_at": "2025-01-15T10:30:00+00:00"
}
]
}
}Lists users who follow the authenticated user (paginated).
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00",
- "followed_at": "2025-01-15T10:30:00+00:00"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Exchanges a one-time assume token (generated by the CMS) for a short-lived
impersonation JWT. The assume token is consumed atomically — it cannot be
reused. The resulting JWT carries act and impersonation claims for
audit traceability.
No Bearer token required — the assume token itself is the credential.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| token required | string = 64 characters The 64-character hex-encoded assume token |
{- "token": "a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2"
}{- "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
- "token_type": "Bearer",
- "expires_in": 315360000,
- "user": {
- "id": 0,
- "name": "string",
- "slug": "string",
- "email": "string",
- "user_label": "normal",
- "avatar": { },
- "email_verified_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Blacklists the current impersonation JWT, ending the impersonation session.
Only works with tokens that carry the impersonation claim.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Search for users with support for sorting and pagination
| page | integer >= 1 Default: 1 The page number for traditional pagination (used by search endpoints) |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| query required | string [ 2 .. 255 ] characters Search query (minimum 2 characters) |
| sort_by | string Default: "relevance" Enum: "relevance" "name" "followers_count" Field to sort results by. When |
| sort_direction | string (SortDirection) Default: "asc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}
], - "links": {
}, - "meta": {
- "current_page": 0,
- "from": 0,
- "last_page": 0,
- "per_page": 0,
- "to": 0,
- "total": 0
}
}Gets a paginated list of users.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a user profile by ID. Includes profile fields (biography, birthdate, gender) and visibility preferences. Email is never exposed in this endpoint.
| user_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "name": "string",
- "slug": "string",
- "user_label": "normal",
- "avatar": { },
- "biography": { },
- "birthdate": { },
- "gender": { },
- "profile_visibility": "public",
- "followers_count": 0,
- "following_count": 0,
- "reviews_count": 0,
- "challenges_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "email_verified_at": { },
- "last_activity_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "preferences": {
- "profile": {
- "show_birthdate": true,
- "show_gender": true
}
}
}
}| slug required | string The unique username/slug of the user |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "name": "string",
- "slug": "string",
- "user_label": "normal",
- "avatar": { },
- "biography": { },
- "birthdate": { },
- "gender": { },
- "profile_visibility": "public",
- "followers_count": 0,
- "following_count": 0,
- "reviews_count": 0,
- "challenges_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "email_verified_at": { },
- "last_activity_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "preferences": {
- "profile": {
- "show_birthdate": true,
- "show_gender": true
}
}
}
}Used for redirecting old Hebban v1 URLs that use original username format (e.g., 'Hans Ramstijn-4759')
| legacySlug required | string The original username from Hebban v1 |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "name": "string",
- "slug": "string",
- "user_label": "normal",
- "avatar": { },
- "biography": { },
- "birthdate": { },
- "gender": { },
- "profile_visibility": "public",
- "followers_count": 0,
- "following_count": 0,
- "reviews_count": 0,
- "challenges_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "email_verified_at": { },
- "last_activity_at": "2019-08-24T14:15:22Z",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "preferences": {
- "profile": {
- "show_birthdate": true,
- "show_gender": true
}
}
}
}Lists users and contributors (authors) the specified user follows.
| user_id required | integer User ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "authors": [
- {
- "id": 456,
- "name": "J.K. Rowling",
- "slug": "jk-rowling",
- "portrait_url": { },
- "portrait_alt_text": { },
- "portrait_attribution": { },
- "followed_at": "2025-01-15T10:30:00+00:00"
}
], - "users": [
- {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00",
- "followed_at": "2025-01-15T10:30:00+00:00"
}
]
}
}Lists users who follow the specified user (paginated).
| user_id required | integer User ID |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00",
- "followed_at": "2025-01-15T10:30:00+00:00"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Lists users who follow the specified contributor (paginated).
| contributor_id required | integer Contributor ID |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00",
- "followed_at": "2025-01-15T10:30:00+00:00"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Idempotently follows the specified user (singleton per follower/followable). Requires authentication.
| user_id required | integer User ID to follow |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Deletes the current user's follow for the specified user (idempotent). Requires authentication. Returns 204 even if there is no follow to delete.
| user_id required | integer User ID to unfollow |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Idempotently follows the specified contributor (singleton per follower/followable). Requires authentication.
| contributor_id required | integer Contributor ID to follow |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Deletes the current user's follow for the specified contributor (idempotent). Requires authentication. Returns 204 even if there is no follow to delete.
| contributor_id required | integer Contributor ID to unfollow |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Lists comments for the review (default is nested with embedded children).
| review_id required | integer Review ID |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 1000 ] Default: 1000 The number of items per page (comments listing only). |
| nested | integer Default: 1 Enum: 0 1 When true (1, default), returns top-level comments with embedded children. When false (0), returns a flat list of all comments (parents and replies) without embedded children. |
| sort_by | string Default: "created_at" Value: "created_at" Field to sort comments by |
| sort_direction | string Default: "asc" Enum: "asc" "desc" Sort direction (asc = oldest-first, desc = newest-first) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "body": "string",
- "parent_id": 0,
- "likes_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "children": [
- { }
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Creates a comment for the review. Requires authentication.
| review_id required | integer Review ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| body required | string Comment text body |
| parent_id | integer or null Optional parent comment ID (single-level threading) |
{- "body": "string",
- "parent_id": 0
}{- "data": {
- "id": 0,
- "body": "string",
- "parent_id": 0,
- "likes_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "children": [
- { }
]
}
}Lists comments for the article (default is nested with embedded children)
| article_id required | integer Article ID |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 1000 ] Default: 1000 The number of items per page (comments listing only). |
| nested | integer Default: 1 Enum: 0 1 When true (1, default), returns top-level comments with embedded children. When false (0), returns a flat list of all comments (parents and replies) without embedded children. |
| sort_by | string Default: "created_at" Value: "created_at" Field to sort comments by |
| sort_direction | string Default: "asc" Enum: "asc" "desc" Sort direction (asc = oldest-first, desc = newest-first) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "body": "string",
- "parent_id": 0,
- "likes_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "children": [
- { }
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Creates a comment for the article. Requires authentication.
| article_id required | integer Article ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| body required | string Comment text body |
| parent_id | integer or null Optional parent comment ID (single-level threading) |
{- "body": "string",
- "parent_id": 0
}{- "data": {
- "id": 0,
- "body": "string",
- "parent_id": 0,
- "likes_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "children": [
- { }
]
}
}Lists comments for the campaign post (default is nested with embedded children). Book club post comments nest up to three levels deep (a reply to a reply to a top-level comment) — the children field recurses accordingly. Returns 404 if the post doesn't exist or isn't live (draft and scheduled posts are indistinguishable from posts that don't exist).
| campaign_post_id required | integer Campaign post ID |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 1000 ] Default: 1000 The number of items per page (comments listing only). |
| nested | integer Default: 1 Enum: 0 1 When true (1, default), returns top-level comments with embedded children. When false (0), returns a flat list of all comments (parents and replies) without embedded children. |
| sort_by | string Default: "created_at" Value: "created_at" Field to sort comments by |
| sort_direction | string Default: "asc" Enum: "asc" "desc" Sort direction (asc = oldest-first, desc = newest-first) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "body": "string",
- "parent_id": 0,
- "likes_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "children": [
- { }
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Creates a comment for the campaign post. Requires authentication; any authenticated user may comment — a book club submission is not required.
When comments are closed for the post, this returns 422 for everyone, including coordinators and editors.
| campaign_post_id required | integer Campaign post ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| body required | string Comment text body |
| parent_id | integer or null Optional parent comment ID (up to three levels of nesting for book club posts) |
{- "body": "string",
- "parent_id": 0
}{- "data": {
- "id": 0,
- "body": "string",
- "parent_id": 0,
- "likes_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "children": [
- { }
]
}
}Lists comments for the event (default is nested with embedded children).
| event_id required | integer Event ID |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 1000 ] Default: 1000 The number of items per page (comments listing only). |
| nested | integer Default: 1 Enum: 0 1 When true (1, default), returns top-level comments with embedded children. When false (0), returns a flat list of all comments (parents and replies) without embedded children. |
| sort_by | string Default: "created_at" Value: "created_at" Field to sort comments by |
| sort_direction | string Default: "asc" Enum: "asc" "desc" Sort direction (asc = oldest-first, desc = newest-first) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "body": "string",
- "parent_id": 0,
- "likes_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "children": [
- { }
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Creates a comment for the event. Requires authentication.
| event_id required | integer Event ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| body required | string Comment text body |
| parent_id | integer or null Optional parent comment ID (single-level threading) |
{- "body": "string",
- "parent_id": 0
}{- "data": {
- "id": 0,
- "body": "string",
- "parent_id": 0,
- "likes_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "children": [
- { }
]
}
}Partially updates the comment body (PATCH semantics). Only the fields provided in the request body will be updated; not all comment fields need to be supplied. Requires authentication; only the author can update their own comment.
| comment_id required | integer Comment ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| body required | string New comment text body |
{- "body": "string"
}{- "data": {
- "id": 0,
- "body": "string",
- "parent_id": 0,
- "likes_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "children": [
- { }
]
}
}Deletes a comment. Requires authentication; only the author can delete their own comment.
| comment_id required | integer Comment ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Idempotently sets the current user's like for the review (singleton per user/review). Requires authentication.
| review_id required | integer Review ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Deletes the current user's like for the review (idempotent). Requires authentication. Returns 204 even if there is no like to delete.
| review_id required | integer Review ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Idempotently sets the current user's like for the article (singleton per user/article). Requires authentication.
| article_id required | integer Article ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Deletes the current user's like for the article (idempotent). Requires authentication. Returns 204 even if there is no like to delete.
| article_id required | integer Article ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Idempotently sets the current user's like for the list (singleton per user/list). Requires authentication.
| list_id required | integer List ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Deletes the current user's like for the list (idempotent). Requires authentication. Returns 204 even if there is no like to delete.
| list_id required | integer List ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Idempotently sets the current user's like for the event (singleton per user/event). Requires authentication.
| event_id required | integer Event ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Deletes the current user's like for the event (idempotent). Requires authentication. Returns 204 even if there is no like to delete.
| event_id required | integer Event ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Idempotently sets the current user's like for the comment (singleton per user/comment). Requires authentication.
| comment_id required | integer Comment ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Deletes the current user's like for the comment (idempotent). Requires authentication. Returns 204 even if there is no like to delete.
| comment_id required | integer Comment ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Lists the authenticated user's reviews with pagination.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "work_type": "book",
- "stars": 1,
- "title": "string",
- "body": "string",
- "editorial": false,
- "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "work": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Lists published reviews created by a specific user with pagination.
| user_id required | integer User ID |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "work_type": "book",
- "stars": 1,
- "title": "string",
- "body": "string",
- "editorial": false,
- "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "work": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Lists published reviews with pagination.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| contributor_id | Array of integers <= 10 items [ items >= 1 ] Filter by contributor ID(s). Supports single or multiple contributors (OR logic). Examples:
Maximum 10 contributor IDs per request. |
| contributor_role | string^(?:A01|A12|A13|B01|B05|B06|C01|E07|Z98|Z99)$... Example: contributor_role=A01 Filter by ONIX contributor role. Based on ONIX codelist 17 (https://ns.editeur.org/onix/en/17). Codes: A01 (Author), A12 (Illustrator), A13 (Photographer), B01 (Editor), B05 (Adapter), B06 (Translator), C01 (Compiled by), E07 (Narrator), Z98 (Various), Z99 (Other). |
| user_id | integer >= 1 Filter records to those created by the given user ID. |
| work_id | integer >= 1 Filter records to those associated with the given work ID. |
| stars | integer [ 1 .. 5 ] Filter reviews to those with exactly this many stars (1-5). |
| min_stars | integer [ 1 .. 5 ] Filter reviews to those with stars greater than or equal to this value (1-5). |
| max_stars | integer [ 1 .. 5 ] Filter reviews to those with stars less than or equal to this value (1-5). |
| user_label[] | Array of strings [ 1 .. 3 ] items Items Enum: "normal" "team" "crew" Filter by the review author's user label (OR logic - reviews whose author has any of the specified labels). The frontend "Hebban" filter is user_label[]=team&user_label[]=crew. |
| length[] | Array of strings [ 1 .. 3 ] items Items Enum: "short" "compact" "extended" Filter by the length of the review text, counted in words; the title does not count (OR logic - reviews of any of the specified lengths). The boundaries currently are: |
| genres[] | Array of integers [ 1 .. 10 ] items Filter by genre IDs (OR logic - works matching any of the specified genres) |
| sort_by | string Default: "created_at" Enum: "id" "created_at" "stars" "likes_count" "comments_count" Field to sort reviews by |
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "work_type": "book",
- "stars": 1,
- "title": "string",
- "body": "string",
- "editorial": false,
- "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "work": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a review by ID.
| review_id required | integer Review ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "work_type": "book",
- "stars": 1,
- "title": "string",
- "body": "string",
- "editorial": false,
- "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "work": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}
}Updates a review. Requires authentication; only the author can update their own review.
| review_id required | integer Review ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| work_type | string Enum: "book" "ebook" "audiobook" Type of work being reviewed |
| stars | integer [ 1 .. 5 ] Star rating from 1 to 5 |
| title | string Review title |
| body | string Review content |
{- "work_type": "book",
- "stars": 1,
- "title": "string",
- "body": "string"
}{- "data": {
- "id": 0,
- "slug": "string",
- "work_type": "book",
- "stars": 1,
- "title": "string",
- "body": "string",
- "editorial": false,
- "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "work": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}
}Deletes a review. Requires authentication; only the author can delete their own review.
| review_id required | integer Review ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}| slug required | string The SEO-friendly slug of the review (format: user-name-over-book-title) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "work_type": "book",
- "stars": 1,
- "title": "string",
- "body": "string",
- "editorial": false,
- "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "work": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}
}| work_id required | integer Work ID |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| user_id | integer >= 1 Filter records to those created by the given user ID. |
| stars | integer [ 1 .. 5 ] Filter reviews to those with exactly this many stars (1-5). |
| min_stars | integer [ 1 .. 5 ] Filter reviews to those with stars greater than or equal to this value (1-5). |
| max_stars | integer [ 1 .. 5 ] Filter reviews to those with stars less than or equal to this value (1-5). |
| user_label[] | Array of strings [ 1 .. 3 ] items Items Enum: "normal" "team" "crew" Filter by the review author's user label (OR logic - reviews whose author has any of the specified labels). The frontend "Hebban" filter is user_label[]=team&user_label[]=crew. |
| length[] | Array of strings [ 1 .. 3 ] items Items Enum: "short" "compact" "extended" Filter by the length of the review text, counted in words; the title does not count (OR logic - reviews of any of the specified lengths). The boundaries currently are: |
| sort_by | string Default: "created_at" Enum: "id" "created_at" "stars" "likes_count" "comments_count" Field to sort reviews by |
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "work_type": "book",
- "stars": 1,
- "title": "string",
- "body": "string",
- "editorial": false,
- "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "work": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}| work_id required | integer Work ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| work_type required | string Enum: "book" "ebook" "audiobook" Type of work being reviewed |
| stars required | integer [ 1 .. 5 ] Star rating from 1 to 5 |
| title required | string Review title |
| body required | string Review content |
{- "work_type": "book",
- "stars": 1,
- "title": "string",
- "body": "string"
}{- "data": {
- "id": 0,
- "slug": "string",
- "work_type": "book",
- "stars": 1,
- "title": "string",
- "body": "string",
- "editorial": false,
- "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "work": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}
}Gets the current user's rating for the work. Requires authentication. Returns 404 if the user has not rated the work.
| work_id required | integer Work ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "rated": true,
- "stars": 1
}Idempotently creates or updates the current user's rating (singleton per user/work). Requires authentication.
| work_id required | integer Work ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| stars required | integer [ 1 .. 5 ] Star rating from 1 to 5 |
{- "stars": 1
}{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Deletes the current user's rating for the work (idempotent). Requires authentication. Returns 204 even if there is no rating to delete. Returns 409 if a review exists for this work by the same user.
| work_id required | integer Work ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Lists reading statuses for the authenticated user, with embedded work data.
Returns reading statuses ordered by most recently added first.
Supports cursor pagination and work sorting via sort_by.
| status required | string Enum: "read" "reading" "want-to-read" Example: reading Reading status filter |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "last_added" Enum: "id" "publication_date_first" "publication_date_latest" "ratings_count" "rating_average" "read_count" "review_count" "favorite_count" "popularity" "title" "contributor" "last_added" "last_read" "own_rating" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "updated_at": "2025-12-11T15:00:00+00:00",
- "finished_on": "2025-12-01",
- "work": {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}, - "count": 0
}Lists reading statuses for a user, with embedded work data.
Returns reading statuses ordered by most recently added first. Supports cursor pagination.
| user_id required | integer Example: 123 User ID |
| status required | string Enum: "read" "reading" "want-to-read" Example: reading Reading status filter |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "last_added" Enum: "id" "publication_date_first" "publication_date_latest" "ratings_count" "rating_average" "read_count" "review_count" "favorite_count" "popularity" "title" "contributor" "last_added" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "updated_at": "2025-12-11T15:00:00+00:00",
- "finished_on": "2025-12-01",
- "work": {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}, - "count": 0
}Lists the users the authenticated user follows who have this work on reading status read (paginated).
Ordered by status_updated_at (when the reading status was last changed), most recently changed first.
The authenticated user is never included. Users with a private profile are excluded; public and protected profiles are included.
Users who only rated the work, without a read status, are not included.
count is the total number of these users across all pages.
| work_id required | integer Work ID |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00",
- "status_updated_at": "2025-12-11T15:00:00+00:00",
- "finished_on": "2025-12-01",
- "rating": { },
- "review": { }
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}, - "count": 0
}Gets the current user's reading status for the work. Requires authentication.
| work_id required | integer Work ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "status": "want_to_read",
- "finished_on": "2025-12-01"
}
}Creates or updates the current user's reading status (singleton per user/work). Requires authentication. When status is 'read', the finish date is recorded as a read entry (one registration per work per calendar year). If finished_on is omitted, it defaults to today in UTC. Changing the status away from 'read' removes the most recent read entry for the work whose year's challenge is still open; entries of closed challenge years are kept.
| work_id required | integer Work ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| status required | string (ReadingStatusState) Enum: "want_to_read" "reading" "read" Current reading status for the work. |
| finished_on | string <date> Optional date (YYYY-MM-DD, UTC). Defaults to today in UTC if omitted. |
{- "status": "want_to_read",
- "finished_on": "2019-08-24"
}{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Clears the current user's reading status for the work. Requires authentication. Always returns 204 even if no reading status existed. Clearing a 'read' status removes the most recent read entry for the work whose year's challenge is still open; entries of closed challenge years are kept.
| work_id required | integer Work ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Lists the current user's read entries for the work, ordered by finished_on descending. Requires authentication.
| work_id required | integer Work ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "user_id": 0,
- "work_id": 0,
- "finished_on": "2019-08-24",
- "source": "manual",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Creates a read entry. A work is registered once per calendar year: a submission for a year already recorded returns the existing entry instead of creating another. This is not a true idempotent operation, so it still returns 201 Created. Requires authentication.
| work_id required | integer Work ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| finished_on required | string <date> Date when the work was finished (YYYY-MM-DD, UTC) |
| source | string (ReadEntrySource) Default: "manual" Enum: "manual" "import" "challenge" Source of the read entry. |
{- "finished_on": "2019-08-24",
- "source": "manual"
}{- "data": {
- "id": 0,
- "user_id": 0,
- "work_id": 0,
- "finished_on": "2019-08-24",
- "source": "manual",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "challenges": [
- {
- "id": 2025,
- "title": "Hebban Reading Challenge 2024",
- "works": [
- 23,
- 24,
- 25
]
}
], - "lists": [
- {
- "id": 1,
- "visibility": "private",
- "preset": "top",
- "title": "top",
- "works": [
- 11,
- 12,
- 13
]
}, - {
- "id": 6,
- "visibility": "private",
- "preset": null,
- "title": "boeken op zolder",
- "works": [
- 23,
- 24,
- 25
]
}
]
}
}| work required | integer The work ID to check membership against |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "challenges": [
- {
- "id": 2025,
- "title": "Hebban Reading Challenge 2024",
- "contains_work": true
}
], - "lists": [
- {
- "id": 1,
- "visibility": "private",
- "preset": "top",
- "title": "top",
- "contains_work": true
}, - {
- "id": 6,
- "visibility": "private",
- "preset": null,
- "title": "boeken op zolder",
- "contains_work": false
}
]
}
}Lists the current user's personal lists. Requires authentication.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "created_at" Enum: "created_at" "title" "likes_count" "works_count" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| preset | boolean Filter lists by preset status. When |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "title": "string",
- "description": { },
- "visibility": "public",
- "is_preset": true,
- "preset": "top",
- "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Creates a personal list for the current user. Requires authentication.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| title | string |
null or string | |
| visibility | string (ListVisibility) Enum: "public" "private" Visibility for personal book lists. |
{- "title": "My favorite books",
- "description": "Books I can read over and over again",
- "visibility": "public"
}{- "data": {
- "id": 0,
- "title": "string",
- "description": { },
- "visibility": "public",
- "is_preset": true,
- "preset": "top",
- "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Gets a personal list. Requires authentication; owners can always view.
| list_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "title": "string",
- "description": { },
- "visibility": "public",
- "is_preset": true,
- "preset": "top",
- "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Updates a personal list. Requires authentication; only the owner can update.
Preset lists (is_preset: true) have a system-managed title and description that cannot be changed. Only visibility can be updated on preset lists. Sending title or description for a preset list returns 422.
| list_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
| title | string |
null or string | |
| visibility | string (ListVisibility) Enum: "public" "private" Visibility for personal book lists. |
{- "title": "Updated List Title",
- "description": { },
- "visibility": "public"
}{- "data": {
- "id": 0,
- "title": "string",
- "description": { },
- "visibility": "public",
- "is_preset": true,
- "preset": "top",
- "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Deletes a personal list. Requires authentication; only the owner can delete.
| list_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Lists works in one of the current user's personal lists. Requires authentication. Supports work sorting via sort_by.
| list_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "last_added" Enum: "id" "publication_date_first" "publication_date_latest" "ratings_count" "rating_average" "read_count" "review_count" "favorite_count" "popularity" "title" "contributor" "last_added" "last_read" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}, - "count": 0
}Adds a work to one of the current user's personal lists. Idempotent — repeated calls succeed without side effects. Requires authentication; only the owner can update.
| list_id required | integer |
| work_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Removes a work from one of the current user's personal lists. Requires authentication; only the owner can update.
| list_id required | integer |
| work_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Lists the specified user's personal lists that are PUBLIC. Requires API token.
| user_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "created_at" Enum: "created_at" "title" "likes_count" "works_count" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| preset | boolean Filter lists by preset status. When |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "title": "string",
- "description": { },
- "visibility": "public",
- "is_preset": true,
- "preset": "top",
- "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a user's personal list if it is PUBLIC.
| user_id required | integer |
| list_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "title": "string",
- "description": { },
- "visibility": "public",
- "is_preset": true,
- "preset": "top",
- "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Lists works in a user's personal list if it is PUBLIC.
| user_id required | integer |
| list_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "last_added" Enum: "id" "publication_date_first" "publication_date_latest" "ratings_count" "rating_average" "read_count" "review_count" "favorite_count" "popularity" "title" "contributor" "last_added" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Returns all challenges the current user has joined, including their pledge target and progress. Use this to display the user's active and past challenges.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "challenge": {
- "id": 0,
- "year": 2000,
- "title": "string",
- "intro": { },
- "expires_at": { },
- "hero_image": {
- "id": 0,
- "url": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}, - "pledge_target": null,
- "works_count": 0,
- "read_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Join a reading challenge. Optionally set a pledge target (number of books to read). Returns 409 if the user has already joined this challenge, or if the challenge has expired (past its end date) — expired challenges no longer accept participants.
| challenge_id required | integer The ID of the challenge to join |
null or integer >= 1 Optional pledge (number of books to read) |
{- "challenge_id": 0,
- "pledge_target": null
}{- "data": {
- "challenge": {
- "id": 0,
- "year": 2000,
- "title": "string",
- "intro": { },
- "expires_at": { },
- "hero_image": {
- "id": 0,
- "url": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}, - "pledge_target": null,
- "works_count": 0,
- "read_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Returns details about a specific challenge the user has joined, including their pledge target, progress, and the list of works they've added to this challenge.
| challenge_id required | integer The ID of the challenge |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "challenge": {
- "id": 0,
- "year": 2000,
- "title": "string",
- "intro": { },
- "expires_at": { },
- "hero_image": {
- "id": 0,
- "url": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}, - "pledge_target": null,
- "works_count": 0,
- "read_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Update your pledge target (number of books to read) for a challenge you've joined. Returns 409 if the challenge has expired and is read-only.
| challenge_id required | integer The ID of the challenge |
null or integer >= 1 Number of books you pledge to read (null to remove pledge) |
{- "pledge_target": null
}{- "data": {
- "challenge": {
- "id": 0,
- "year": 2000,
- "title": "string",
- "intro": { },
- "expires_at": { },
- "hero_image": {
- "id": 0,
- "url": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}, - "pledge_target": null,
- "works_count": 0,
- "read_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Leave a challenge you've joined. This removes your participation and all works you've added to this challenge. Returns 409 if the challenge has expired and is read-only.
| challenge_id required | integer The ID of the challenge to leave |
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Lists works in the current user's challenge participation list for a given challenge.
Once the challenge has expired, the list is frozen and only returns works with a read
entry linked to that challenge. Other works are no longer part of the frozen list:
they are not returned and no longer counted in works_count, which keeps matching
the number of items returned here. Requires authentication.
| challenge_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "challenge_context": {
- "reading_status": "want_to_read",
- "has_read": true
}
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Adds a work to the current user's challenge participation list. Idempotent — repeated calls succeed without side effects. Requires authentication.
| challenge_id required | integer |
| work_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Removes a work from the current user's challenge participation list. Requires authentication.
| challenge_id required | integer |
| work_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}Lists a user's public challenge participation lists
| user_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "challenge": {
- "id": 0,
- "year": 2000,
- "title": "string",
- "intro": { },
- "expires_at": { },
- "hero_image": {
- "id": 0,
- "url": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}, - "pledge_target": null,
- "works_count": 0,
- "read_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a user's participation in a specific challenge
| user_id required | integer |
| challenge_id required | integer The ID of the challenge |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "challenge": {
- "id": 0,
- "year": 2000,
- "title": "string",
- "intro": { },
- "expires_at": { },
- "hero_image": {
- "id": 0,
- "url": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}, - "pledge_target": null,
- "works_count": 0,
- "read_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Lists the works a user has added to their challenge participation.
Once the challenge has expired, the list is frozen and only returns works with a read
entry linked to that challenge. Other works are no longer part of the frozen list:
they are not returned and no longer counted in works_count, which keeps matching
the number of items returned here.
| user_id required | integer |
| challenge_id required | integer The ID of the challenge |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "challenge_context": {
- "reading_status": "want_to_read",
- "has_read": true
}
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Search for challenges with support for sorting and pagination
| page | integer >= 1 Default: 1 The page number for traditional pagination (used by search endpoints) |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| query required | string [ 2 .. 255 ] characters Search query (minimum 2 characters) |
| sort_by | string Default: "relevance" Enum: "relevance" "published_at" "title" Field to sort results by. When |
| sort_direction | string (SortDirection) Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "year": 2000,
- "title": "string",
- "intro": { },
- "expires_at": { },
- "hero_image": {
- "id": 0,
- "url": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "current_page": 0,
- "from": 0,
- "last_page": 0,
- "per_page": 0,
- "to": 0,
- "total": 0
}
}Lists challenges available to join, filtered by year.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| from_year | integer [ 2000 .. 2100 ] Default: 2025 Filter challenges from this year onwards (inclusive) |
| sort_direction | string (SortDirection) Default: "desc" Enum: "asc" "desc" Sort direction by year (desc = newest first, asc = oldest first) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "year": 2000,
- "title": "string",
- "intro": { },
- "expires_at": { },
- "hero_image": {
- "id": 0,
- "url": "string"
}, - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Returns aggregated statistics for a specific challenge including participant count, total pledges, books read, and completion count.
| challenge required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "participants": 0,
- "total_pledges": 0,
- "books_read": 0,
- "completed": 0
}
}Lists works with cursor-based pagination.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "id" Enum: "id" "publication_date_first" "publication_date_latest" "ratings_count" "rating_average" "read_count" "read_count_30d" "review_count" "favorite_count" "popularity" "title" "contributor" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| isbn | string [ 4 .. 13 ] characters ^[0-9]{4,13}$ Optional filter on edition ISBN-13. Provide 4–13 digits; results include works whose edition ISBN-13 starts with this prefix. |
| genres[] | Array of integers [ 1 .. 10 ] items Filter by genre IDs (OR logic - works matching any of the specified genres) |
| language | Array of strings Items Enum: "dut" "eng" "other" Filter by language code (ONIX Codelist 74, based on ISO 639-2/B).
Supports single value, comma-separated values, or array syntax.
|
| source[] | Array of strings [ 1 .. 3 ] items Items Enum: "cb" "titelbank" "v1" Filter by work source (OR logic - works matching any of the specified sources) |
| publication_date_first_from | string <date> Example: publication_date_first_from=2026-03-10 Include works with publication_date_first on or after this date (YYYY-MM-DD). Works without a first publication date are excluded. |
| publication_date_first_until | string <date> Example: publication_date_first_until=2026-04-09 Include works with publication_date_first on or before this date (YYYY-MM-DD). Works without a first publication date are excluded. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a work by ID.
| work_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Look up a work by its normalized ISBN-13.
The ISBN must be provided as a 13-digit ISBN-13 without separators (no spaces or hyphens).
| isbn required | string = 13 characters ^[0-9]{13}$ 13-digit ISBN-13 without separators. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Fetches multiple works by their IDs in a single request.
Behavior:
ids=1,5,5 returns work 5 twice)Example: GET /works/bulk?ids=1,6,5,5 returns 4 works in order: [1, 6, 5, 5]
| ids required | string^\d+(,\d+)*$ Example: ids=1,6,5,5 Comma-separated list of work IDs (max 100). Duplicates are allowed and will return the same work multiple times. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
]
}Returns works from the "Uitgelicht" (Featured) editorial list. Works are ordered by their position in the list as curated by editors.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
]
}Returns up to 100 works first published in the last 30 days, sorted by popularity (descending). Works with fewer than 2 ratings are excluded so a single rating cannot place a work at the top.
The list is fully algorithmic and refreshes with the current date and platform popularity; no editorial curation applies.
| source[] | Array of strings [ 1 .. 3 ] items Items Enum: "cb" "titelbank" "v1" Filter by work source (OR logic - works matching any of the specified sources) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
]
}Returns up to 100 works that have been recently finished by users across the platform. Each work is shown once, ordered by most recent finish date.
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
]
}Returns up to 100 works that have been recently reviewed by users across the platform. Each work is shown once, ordered by most recent review date.
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
]
}Returns works expected to become available within the next 3 months (configurable).
Upcoming works have:
Works are ordered by publication_date_first ascending (soonest first).
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| isbn | string [ 4 .. 13 ] characters ^[0-9]{4,13}$ Optional filter on edition ISBN-13. Provide 4–13 digits; results include works whose edition ISBN-13 starts with this prefix. |
| genres[] | Array of integers [ 1 .. 10 ] items Filter by genre IDs (OR logic - works matching any of the specified genres) |
| language | Array of strings Items Enum: "dut" "eng" "other" Filter by language code (ONIX Codelist 74, based on ISO 639-2/B).
Supports single value, comma-separated values, or array syntax.
|
| source[] | Array of strings [ 1 .. 3 ] items Items Enum: "cb" "titelbank" "v1" Filter by work source (OR logic - works matching any of the specified sources) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Search for works with support for sorting and pagination
| page | integer >= 1 Default: 1 The page number for traditional pagination (used by search endpoints) |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| query required | string [ 2 .. 255 ] characters Search query (minimum 2 characters) |
| sort_by | string Default: "relevance" Enum: "relevance" "publication_date_first" "publication_date_latest" "title" "ratings_count" "rating_average" "read_count" "read_count_30d" "review_count" "favorite_count" "popularity" "id" Field to sort search results by. When |
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| genres[] | Array of integers [ 1 .. 10 ] items Filter by genre IDs (OR logic - works matching any of the specified genres) |
| language | Array of strings Items Enum: "dut" "eng" "other" Filter by language code (ONIX Codelist 74, based on ISO 639-2/B).
Supports single value, comma-separated values, or array syntax.
|
| source[] | Array of strings [ 1 .. 3 ] items Items Enum: "cb" "titelbank" "v1" Filter by work source (OR logic - works matching any of the specified sources) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
], - "links": {
}, - "meta": {
- "current_page": 0,
- "from": 0,
- "last_page": 0,
- "per_page": 0,
- "to": 0,
- "total": 0
}
}Gets a work by slug.
| slug required | string |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Lists events for the work with pagination.
| work_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| period | string Default: "future" Enum: "future" "past" "all" Filter events by period. Default is future. |
| sort_by | string Default: "starts_on" Enum: "starts_on" "created_at" Sort column (whitelisted). Defaults to starts_on. |
| sort_direction | string (SortDirection) Default: "desc" Enum: "asc" "desc" Sort direction. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "summary": { },
- "description": { },
- "city": { },
- "meta_title": { },
- "meta_description": { },
- "starts_on": { },
- "starts_at": { },
- "ends_on": { },
- "ends_at": { },
- "access_type": { },
- "price": { },
- "registration_method": { },
- "registration_url": { },
- "registration_email": { },
- "registration_text": { },
- "kind": { },
- "venue_name": { },
- "venue_address": { },
- "venue_url": { },
- "organizer_name": { },
- "organizer_email": { },
- "organizer_url": { },
- "hero_image": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Returns daily Hebban rank snapshots for a work, ordered chronologically (oldest first). Each entry represents the work's rank on a specific date (1 = most popular, up to 10,000). Data is available from November 2018. Works that are not currently ranked may still have historical data.
| work_id required | integer The ID of the work |
| from | string <date> Start date for the history range (inclusive). Defaults to 1 year ago. Must not be in the future. |
| to | string <date> End date for the history range (inclusive). Defaults to today. Must not be in the future. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "ranked_at": "2026-03-15",
- "rank": 42
}
]
}Returns personalized recommendations for a work based on collaborative filtering. First request returns 202 and triggers generation. Subsequent requests return 200 with cached results. Recommendations are grouped into 8 subsets based on author/genre/recency similarity. Failed generation returns 200 with status=failed and error message.
| work_id required | integer The ID of the work |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "work_id": 123,
- "status": "completed",
- "subsets": {
- "same_author_same_genre_recent": [
- 1,
- 2,
- 3,
- 4,
- 5
], - "same_author_same_genre_not_recent": [
- 6,
- 7,
- 8,
- 9,
- 10
], - "same_author_different_genre_recent": [
- 11,
- 12,
- 13,
- 14,
- 15
], - "same_author_different_genre_not_recent": [
- 16,
- 17,
- 18,
- 19,
- 20
], - "different_author_same_genre_recent": [
- 21,
- 22,
- 23,
- 24,
- 25
], - "different_author_same_genre_not_recent": [
- 26,
- 27,
- 28,
- 29,
- 30
], - "different_author_different_genre_recent": [
- 31,
- 32,
- 33,
- 34,
- 35
], - "different_author_different_genre_not_recent": [
- 36,
- 37,
- 38,
- 39,
- 40
]
}, - "error": "Insufficient rating data",
- "generated_at": "2026-01-09T12:00:00Z"
}
}Search for contributors (authors) by name with support for sorting and pagination
| page | integer >= 1 Default: 1 The page number for traditional pagination (used by search endpoints) |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| query required | string [ 2 .. 255 ] characters Search query (minimum 2 characters) |
| sort_by | string Default: "relevance" Enum: "relevance" "name" "followers_count" "works_count" "popularity" Field to sort results by. When |
| sort_direction | string (SortDirection) Default: "asc" Enum: "asc" "desc" Sort direction |
| contributor_role | Array of strings[ items^(?:A01|A12|A13|B01|B05|B06|C01|E07|Z98|Z99)$... ] Example: contributor_role=A01,B06 Filter by ONIX contributor role(s). Accepts comma-separated codes or array. Results include contributors with any of the specified roles (OR logic). Based on ONIX codelist 17 (https://ns.editeur.org/onix/en/17). Codes: A01 (Author), A12 (Illustrator), A13 (Photographer), B01 (Editor), B05 (Adapter), B06 (Translator), C01 (Compiled by), E07 (Narrator), Z98 (Various), Z99 (Other). |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "biography": { },
- "portrait_url": { },
- "portrait_alt_text": { },
- "portrait_attribution": { },
- "user_id": 42,
- "user_slug": "jane-doe",
- "followers_count": 42,
- "works_count": 15,
- "article_count": 8,
- "event_count": 3,
- "roles": [
- "A01",
- "B06"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "current_page": 0,
- "from": 0,
- "last_page": 0,
- "per_page": 0,
- "to": 0,
- "total": 0
}
}Lists contributors with pagination.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "popularity" Enum: "id" "name" "followers_count" "works_count" "popularity" Field to sort contributors by |
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "biography": { },
- "portrait_url": { },
- "portrait_alt_text": { },
- "portrait_attribution": { },
- "user_id": 42,
- "user_slug": "jane-doe",
- "followers_count": 42,
- "works_count": 15,
- "article_count": 8,
- "event_count": 3,
- "roles": [
- "A01",
- "B06"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Fetches multiple contributors by their IDs in a single request.
Behavior:
ids=1,5,5 returns contributor 5 twice)Example: GET /contributors/bulk?ids=1,6,5,5 returns 4 contributors in order: [1, 6, 5, 5]
| ids required | string^\d+(,\d+)*$ Example: ids=1,6,5,5 Comma-separated list of contributor IDs (max 100). Duplicates are allowed and will return the same contributor multiple times. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "biography": { },
- "portrait_url": { },
- "portrait_alt_text": { },
- "portrait_attribution": { },
- "user_id": 42,
- "user_slug": "jane-doe",
- "followers_count": 42,
- "works_count": 15,
- "article_count": 8,
- "event_count": 3,
- "roles": [
- "A01",
- "B06"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Gets a contributor by ID.
| contributor_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "biography": { },
- "portrait_url": { },
- "portrait_alt_text": { },
- "portrait_attribution": { },
- "user_id": 42,
- "user_slug": "jane-doe",
- "followers_count": 42,
- "works_count": 15,
- "article_count": 8,
- "event_count": 3,
- "roles": [
- "A01",
- "B06"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Lists works for the contributor with pagination.
| contributor_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| contributor_role | string^(?:A01|A12|A13|B01|B05|B06|C01|E07|Z98|Z99)$... Example: contributor_role=A01 Filter by ONIX contributor role. Based on ONIX codelist 17 (https://ns.editeur.org/onix/en/17). Codes: A01 (Author), A12 (Illustrator), A13 (Photographer), B01 (Editor), B05 (Adapter), B06 (Translator), C01 (Compiled by), E07 (Narrator), Z98 (Various), Z99 (Other). |
| sort_by | string Default: "id" Enum: "id" "publication_date_first" "publication_date_latest" "ratings_count" "rating_average" "read_count" "read_count_30d" "review_count" "favorite_count" "popularity" "title" "contributor" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| isbn | string [ 4 .. 13 ] characters ^[0-9]{4,13}$ Optional filter on edition ISBN-13. Provide 4–13 digits; results include works whose edition ISBN-13 starts with this prefix. |
| genres[] | Array of integers [ 1 .. 10 ] items Filter by genre IDs (OR logic - works matching any of the specified genres) |
| language | Array of strings Items Enum: "dut" "eng" "other" Filter by language code (ONIX Codelist 74, based on ISO 639-2/B).
Supports single value, comma-separated values, or array syntax.
|
| source[] | Array of strings [ 1 .. 3 ] items Items Enum: "cb" "titelbank" "v1" Filter by work source (OR logic - works matching any of the specified sources) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Lists events for the contributor with pagination.
| contributor_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| period | string Default: "future" Enum: "future" "past" "all" Filter events by period. Default is future. |
| sort_by | string Default: "starts_on" Enum: "starts_on" "created_at" Sort column (whitelisted). Defaults to starts_on. |
| sort_direction | string (SortDirection) Default: "desc" Enum: "asc" "desc" Sort direction. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "summary": { },
- "description": { },
- "city": { },
- "meta_title": { },
- "meta_description": { },
- "starts_on": { },
- "starts_at": { },
- "ends_on": { },
- "ends_at": { },
- "access_type": { },
- "price": { },
- "registration_method": { },
- "registration_url": { },
- "registration_email": { },
- "registration_text": { },
- "kind": { },
- "venue_name": { },
- "venue_address": { },
- "venue_url": { },
- "organizer_name": { },
- "organizer_email": { },
- "organizer_url": { },
- "hero_image": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a contributor by slug.
| slug required | string |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "biography": { },
- "portrait_url": { },
- "portrait_alt_text": { },
- "portrait_attribution": { },
- "user_id": 42,
- "user_slug": "jane-doe",
- "followers_count": 42,
- "works_count": 15,
- "article_count": 8,
- "event_count": 3,
- "roles": [
- "A01",
- "B06"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Lists publishers with pagination.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "gau": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a publisher by ID.
| publisher_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "name": "string",
- "gau": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Lists works for the publisher with pagination.
| publisher_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "id" Enum: "id" "publication_date_first" "publication_date_latest" "ratings_count" "rating_average" "read_count" "read_count_30d" "review_count" "favorite_count" "popularity" "title" "contributor" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| isbn | string [ 4 .. 13 ] characters ^[0-9]{4,13}$ Optional filter on edition ISBN-13. Provide 4–13 digits; results include works whose edition ISBN-13 starts with this prefix. |
| genres[] | Array of integers [ 1 .. 10 ] items Filter by genre IDs (OR logic - works matching any of the specified genres) |
| language | Array of strings Items Enum: "dut" "eng" "other" Filter by language code (ONIX Codelist 74, based on ISO 639-2/B).
Supports single value, comma-separated values, or array syntax.
|
| source[] | Array of strings [ 1 .. 3 ] items Items Enum: "cb" "titelbank" "v1" Filter by work source (OR logic - works matching any of the specified sources) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a publisher by slug.
| slug required | string |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "name": "string",
- "gau": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Lists genres with pagination.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a genre by ID.
| genre_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Lists works for the genre with pagination.
| genre_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "id" Enum: "id" "publication_date_first" "publication_date_latest" "ratings_count" "rating_average" "read_count" "read_count_30d" "review_count" "favorite_count" "popularity" "title" "contributor" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| isbn | string [ 4 .. 13 ] characters ^[0-9]{4,13}$ Optional filter on edition ISBN-13. Provide 4–13 digits; results include works whose edition ISBN-13 starts with this prefix. |
| language | Array of strings Items Enum: "dut" "eng" "other" Filter by language code (ONIX Codelist 74, based on ISO 639-2/B).
Supports single value, comma-separated values, or array syntax.
|
| source[] | Array of strings [ 1 .. 3 ] items Items Enum: "cb" "titelbank" "v1" Filter by work source (OR logic - works matching any of the specified sources) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a genre by slug.
| slug required | string |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Lists the works in a series, paginated. Works are ordered by part number high-to-low; works without a part number follow, newest first.
| slug required | string |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| isbn | string [ 4 .. 13 ] characters ^[0-9]{4,13}$ Optional filter on edition ISBN-13. Provide 4–13 digits; results include works whose edition ISBN-13 starts with this prefix. |
| language | Array of strings Items Enum: "dut" "eng" "other" Filter by language code (ONIX Codelist 74, based on ISO 639-2/B).
Supports single value, comma-separated values, or array syntax.
|
| source[] | Array of strings [ 1 .. 3 ] items Items Enum: "cb" "titelbank" "v1" Filter by work source (OR logic - works matching any of the specified sources) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a series by slug.
| slug required | string |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "title": "string",
- "works_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Lists the Hebban 1000 entries ordered by rank for a specific year. Defaults to the most recent year that has entries when no year is provided.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| year | integer >= 2018 Filter entries for a specific Hebban 1000 year |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 1,
- "year": 2025,
- "rank": 1,
- "previous_rank": 3,
- "work": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Returns the work IDs of the Hebban 1000 for a specific year, ordered by rank. Defaults to the most recent year that has entries when no year is provided. Intended for clients that need to compute overlap with a user's read books.
| year | integer >= 2018 Filter entries for a specific Hebban 1000 year |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- 0
]
}Search for articles with support for sorting and pagination
| page | integer >= 1 Default: 1 The page number for traditional pagination (used by search endpoints) |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| query required | string [ 2 .. 255 ] characters Search query (minimum 2 characters) |
| type | Array of strings (ArticleType) Items Enum: "news" "interview" "book_of_the_month" "inspiration" "book_club" "opinion" "community" "advertorial" "promotion" "deepdive" "quiz" Filter by type. Accepts single value, comma-separated values, or array syntax.
Examples: |
| sort_by | string Default: "relevance" Enum: "relevance" "published_at" "title" "likes_count" "comments_count" Field to sort results by. When |
| sort_direction | string (SortDirection) Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "title": "string",
- "hero": { },
- "intro": "string",
- "slug": "string",
- "meta_title": { },
- "meta_description": { },
- "type": "news",
- "status": "draft",
- "user": { },
- "blocks": [
- {
- "id": 0,
- "type": "text",
- "data": {
- "text": "string"
}, - "order": 0
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "current_page": 0,
- "from": 0,
- "last_page": 0,
- "per_page": 0,
- "to": 0,
- "total": 0
}
}| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| status | string Enum: "draft" "scheduled" "published" "archived" Example: status=published Filter by publication status |
| type | Array of strings (ArticleType) Items Enum: "news" "interview" "book_of_the_month" "inspiration" "book_club" "opinion" "community" "advertorial" "promotion" "deepdive" "quiz" Filter by type. Accepts single value, comma-separated values, or array syntax.
Examples: |
| contributor_id | Array of integers <= 10 items [ items >= 1 ] Filter articles to those associated with the given contributor ID(s).
Supports single value, comma-separated, or array syntax (OR logic).
Examples: |
| work_id | Array of integers <= 10 items [ items >= 1 ] Filter articles to those associated with the given work ID(s).
Supports single value, comma-separated, or array syntax (OR logic).
Examples: |
| book_list_id | Array of integers <= 10 items [ items >= 1 ] Filter articles to those associated with the given book list ID(s).
Supports single value, comma-separated, or array syntax (OR logic).
Examples: |
| related_article_id | Array of integers <= 10 items [ items >= 1 ] Filter articles to those that reference or link to the given article ID(s).
Supports single value, comma-separated, or array syntax (OR logic).
Examples: |
| sort_by | string Default: "id" Enum: "id" "created_at" "updated_at" "published_at" "scheduled_at" "title" Field to sort results by. Note: Articles with null values in the sort column are excluded from results. |
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "title": "string",
- "hero": { },
- "intro": "string",
- "slug": "string",
- "meta_title": { },
- "meta_description": { },
- "type": "news",
- "status": "draft",
- "user": { },
- "blocks": [
- {
- "id": 0,
- "type": "text",
- "data": {
- "text": "string"
}, - "order": 0
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}| article_id required | integer |
| preview_id | string <uuid> Short-lived preview token generated by the CMS for this item, as carried by its preview link. Send it when fetching the item for a preview. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "title": "string",
- "hero": { },
- "intro": "string",
- "slug": "string",
- "meta_title": { },
- "meta_description": { },
- "type": "news",
- "status": "draft",
- "user": { },
- "blocks": [
- {
- "id": 0,
- "type": "text",
- "data": {
- "text": "string"
}, - "order": 0
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}| slug required | string |
| preview_id | string <uuid> Short-lived preview token generated by the CMS for this item, as carried by its preview link. Send it when fetching the item for a preview. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "title": "string",
- "hero": { },
- "intro": "string",
- "slug": "string",
- "meta_title": { },
- "meta_description": { },
- "type": "news",
- "status": "draft",
- "user": { },
- "blocks": [
- {
- "id": 0,
- "type": "text",
- "data": {
- "text": "string"
}, - "order": 0
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Returns curated featured events ordered by position.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "summary": { },
- "description": { },
- "city": { },
- "meta_title": { },
- "meta_description": { },
- "starts_on": { },
- "starts_at": { },
- "ends_on": { },
- "ends_at": { },
- "access_type": { },
- "price": { },
- "registration_method": { },
- "registration_url": { },
- "registration_email": { },
- "registration_text": { },
- "kind": { },
- "venue_name": { },
- "venue_address": { },
- "venue_url": { },
- "organizer_name": { },
- "organizer_email": { },
- "organizer_url": { },
- "hero_image": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Search for events with support for sorting and pagination
| page | integer >= 1 Default: 1 The page number for traditional pagination (used by search endpoints) |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| query required | string [ 2 .. 255 ] characters Search query (minimum 2 characters) |
| sort_by | string Default: "relevance" Enum: "relevance" "starts_on" "title" Field to sort results by. When |
| sort_direction | string (SortDirection) Default: "asc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "summary": { },
- "description": { },
- "city": { },
- "meta_title": { },
- "meta_description": { },
- "starts_on": { },
- "starts_at": { },
- "ends_on": { },
- "ends_at": { },
- "access_type": { },
- "price": { },
- "registration_method": { },
- "registration_url": { },
- "registration_email": { },
- "registration_text": { },
- "kind": { },
- "venue_name": { },
- "venue_address": { },
- "venue_url": { },
- "organizer_name": { },
- "organizer_email": { },
- "organizer_url": { },
- "hero_image": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "current_page": 0,
- "from": 0,
- "last_page": 0,
- "per_page": 0,
- "to": 0,
- "total": 0
}
}| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| period | string Default: "future" Enum: "future" "past" "all" Filter events by period. Default is future. |
| sort_by | string Default: "starts_on" Enum: "starts_on" "created_at" Sort column (whitelisted). Defaults to starts_on. |
| sort_direction | string (SortDirection) Default: "desc" Enum: "asc" "desc" Sort direction. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "summary": { },
- "description": { },
- "city": { },
- "meta_title": { },
- "meta_description": { },
- "starts_on": { },
- "starts_at": { },
- "ends_on": { },
- "ends_at": { },
- "access_type": { },
- "price": { },
- "registration_method": { },
- "registration_url": { },
- "registration_email": { },
- "registration_text": { },
- "kind": { },
- "venue_name": { },
- "venue_address": { },
- "venue_url": { },
- "organizer_name": { },
- "organizer_email": { },
- "organizer_url": { },
- "hero_image": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Lists works for the event with pagination.
| event_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "id" Enum: "id" "publication_date_first" "publication_date_latest" "ratings_count" "rating_average" "read_count" "read_count_30d" "review_count" "favorite_count" "popularity" "title" "contributor" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| isbn | string [ 4 .. 13 ] characters ^[0-9]{4,13}$ Optional filter on edition ISBN-13. Provide 4–13 digits; results include works whose edition ISBN-13 starts with this prefix. |
| genres[] | Array of integers [ 1 .. 10 ] items Filter by genre IDs (OR logic - works matching any of the specified genres) |
| language | Array of strings Items Enum: "dut" "eng" "other" Filter by language code (ONIX Codelist 74, based on ISO 639-2/B).
Supports single value, comma-separated values, or array syntax.
|
| source[] | Array of strings [ 1 .. 3 ] items Items Enum: "cb" "titelbank" "v1" Filter by work source (OR logic - works matching any of the specified sources) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Lists contributors for the event with pagination.
| event_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "popularity" Enum: "id" "name" "followers_count" "works_count" "popularity" Field to sort contributors by |
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "biography": { },
- "portrait_url": { },
- "portrait_alt_text": { },
- "portrait_attribution": { },
- "user_id": 42,
- "user_slug": "jane-doe",
- "followers_count": 42,
- "works_count": 15,
- "article_count": 8,
- "event_count": 3,
- "roles": [
- "A01",
- "B06"
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}| slug required | string |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "title": "string",
- "summary": { },
- "description": { },
- "city": { },
- "meta_title": { },
- "meta_description": { },
- "starts_on": { },
- "starts_at": { },
- "ends_on": { },
- "ends_at": { },
- "access_type": { },
- "price": { },
- "registration_method": { },
- "registration_url": { },
- "registration_email": { },
- "registration_text": { },
- "kind": { },
- "venue_name": { },
- "venue_address": { },
- "venue_url": { },
- "organizer_name": { },
- "organizer_email": { },
- "organizer_url": { },
- "hero_image": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}List published static pages with cursor-based pagination.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "title": "string",
- "hero": { },
- "intro": { },
- "slug": "string",
- "meta_title": { },
- "meta_description": { },
- "blocks": [
- {
- "id": 0,
- "type": "text",
- "data": {
- "text": "string"
}, - "order": 0
}
], - "is_published": true,
- "published_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}| page_id required | integer |
| preview_id | string <uuid> Short-lived preview token generated by the CMS for this item, as carried by its preview link. Send it when fetching the item for a preview. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "title": "string",
- "hero": { },
- "intro": { },
- "slug": "string",
- "meta_title": { },
- "meta_description": { },
- "blocks": [
- {
- "id": 0,
- "type": "text",
- "data": {
- "text": "string"
}, - "order": 0
}
], - "is_published": true,
- "published_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}| slug required | string |
| preview_id | string <uuid> Short-lived preview token generated by the CMS for this item, as carried by its preview link. Send it when fetching the item for a preview. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "title": "string",
- "hero": { },
- "intro": { },
- "slug": "string",
- "meta_title": { },
- "meta_description": { },
- "blocks": [
- {
- "id": 0,
- "type": "text",
- "data": {
- "text": "string"
}, - "order": 0
}
], - "is_published": true,
- "published_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Search for tags with support for sorting and pagination
| page | integer >= 1 Default: 1 The page number for traditional pagination (used by search endpoints) |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| query required | string [ 2 .. 255 ] characters Search query (minimum 2 characters) |
| sort_by | string Default: "relevance" Enum: "relevance" "articles_count" "name" Field to sort results by. When |
| sort_direction | string (SortDirection) Default: "asc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction",
- "articles_count": 5,
- "events_count": 3,
- "lists_count": 7,
- "works_count": 12,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "current_page": 0,
- "from": 0,
- "last_page": 0,
- "per_page": 0,
- "to": 0,
- "total": 0
}
}Lists tags with pagination.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction",
- "articles_count": 5,
- "events_count": 3,
- "lists_count": 7,
- "works_count": 12,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Gets a tag by ID.
| tag_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 42,
- "name": "fiction",
- "slug": "fiction",
- "articles_count": 5,
- "events_count": 3,
- "lists_count": 7,
- "works_count": 12,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Lists all works associated with a specific tag with pagination.
| tag_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "id" Enum: "id" "publication_date_first" "publication_date_latest" "ratings_count" "rating_average" "read_count" "read_count_30d" "review_count" "favorite_count" "popularity" "title" "contributor" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| isbn | string [ 4 .. 13 ] characters ^[0-9]{4,13}$ Optional filter on edition ISBN-13. Provide 4–13 digits; results include works whose edition ISBN-13 starts with this prefix. |
| genres[] | Array of integers [ 1 .. 10 ] items Filter by genre IDs (OR logic - works matching any of the specified genres) |
| language | Array of strings Items Enum: "dut" "eng" "other" Filter by language code (ONIX Codelist 74, based on ISO 639-2/B).
Supports single value, comma-separated values, or array syntax.
|
| source[] | Array of strings [ 1 .. 3 ] items Items Enum: "cb" "titelbank" "v1" Filter by work source (OR logic - works matching any of the specified sources) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 12345,
- "slug": "de-ontdekking-van-de-kroket-barry-nommish",
- "nstc": "978901234567",
- "title": "De ontdekking van de kroket",
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "language_code": "dut",
- "additional_content": "Tijdloze verhandeling over de kroket.",
- "bestseller_60": "Staat nu al 18 weken op nummer 1, we weten allemaal waarom.",
- "publication_date_first": "1992-01-01",
- "publication_date_latest": "2023-05-15",
- "expected_availability_date": "2026-03-15",
- "availability_status": "available",
- "source": "cb",
- "rating_average": 4.9,
- "ratings_count": 1723,
- "read_count": 542,
- "read_count_30d": 87,
- "hebban_rank": 42,
- "hebban_rank_highest": 15,
- "hebban_1000_rank": 128,
- "is_sponsored": false,
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Lists all articles associated with a specific tag with pagination.
| tag_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| status | string Enum: "draft" "scheduled" "published" "archived" Example: status=published Filter by publication status |
| type | Array of strings (ArticleType) Items Enum: "news" "interview" "book_of_the_month" "inspiration" "book_club" "opinion" "community" "advertorial" "promotion" "deepdive" "quiz" Filter by type. Accepts single value, comma-separated values, or array syntax.
Examples: |
| contributor_id | Array of integers <= 10 items [ items >= 1 ] Filter articles to those associated with the given contributor ID(s).
Supports single value, comma-separated, or array syntax (OR logic).
Examples: |
| work_id | Array of integers <= 10 items [ items >= 1 ] Filter articles to those associated with the given work ID(s).
Supports single value, comma-separated, or array syntax (OR logic).
Examples: |
| book_list_id | Array of integers <= 10 items [ items >= 1 ] Filter articles to those associated with the given book list ID(s).
Supports single value, comma-separated, or array syntax (OR logic).
Examples: |
| related_article_id | Array of integers <= 10 items [ items >= 1 ] Filter articles to those that reference or link to the given article ID(s).
Supports single value, comma-separated, or array syntax (OR logic).
Examples: |
| sort_by | string Default: "id" Enum: "id" "created_at" "updated_at" "published_at" "scheduled_at" "title" Field to sort results by. Note: Articles with null values in the sort column are excluded from results. |
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "title": "string",
- "hero": { },
- "intro": "string",
- "slug": "string",
- "meta_title": { },
- "meta_description": { },
- "type": "news",
- "status": "draft",
- "user": { },
- "blocks": [
- {
- "id": 0,
- "type": "text",
- "data": {
- "text": "string"
}, - "order": 0
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Lists all events associated with a specific tag with pagination.
| tag_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| period | string Default: "future" Enum: "future" "past" "all" Filter events by period. Default is future. |
| sort_by | string Default: "starts_on" Enum: "starts_on" "created_at" Sort column (whitelisted). Defaults to starts_on. |
| sort_direction | string (SortDirection) Default: "desc" Enum: "asc" "desc" Sort direction. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "summary": { },
- "description": { },
- "city": { },
- "meta_title": { },
- "meta_description": { },
- "starts_on": { },
- "starts_at": { },
- "ends_on": { },
- "ends_at": { },
- "access_type": { },
- "price": { },
- "registration_method": { },
- "registration_url": { },
- "registration_email": { },
- "registration_text": { },
- "kind": { },
- "venue_name": { },
- "venue_address": { },
- "venue_url": { },
- "organizer_name": { },
- "organizer_email": { },
- "organizer_url": { },
- "hero_image": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Lists all book lists associated with a specific tag with pagination.
| tag_id required | integer |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "created_at" Enum: "created_at" "title" "likes_count" "works_count" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "status": "draft",
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "template": { },
- "summary": { },
- "description": { },
- "hero_image": { },
- "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}| slug required | string |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 42,
- "name": "fiction",
- "slug": "fiction",
- "articles_count": 5,
- "events_count": 3,
- "lists_count": 7,
- "works_count": 12,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Returns curated book club campaigns ordered by position.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Returns curated giveaway campaigns ordered by position.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Returns curated featured book club campaigns ordered by position.
Deprecated in favor of GET /curated/book-clubs.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Returns curated featured giveaway campaigns ordered by position.
Deprecated in favor of GET /curated/giveaways.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Search for campaigns with support for sorting and pagination
| page | integer >= 1 Default: 1 The page number for traditional pagination (used by search endpoints) |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| query required | string [ 2 .. 255 ] characters Search query (minimum 2 characters) |
| sort_by | string Default: "relevance" Enum: "relevance" "published_at" "title" Field to sort results by. When |
| sort_direction | string (SortDirection) Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "current_page": 0,
- "from": 0,
- "last_page": 0,
- "per_page": 0,
- "to": 0,
- "total": 0
}
}| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| status | string Enum: "draft" "scheduled" "published" "archived" Example: status=published Filter by publication status |
| type | Array of strings (CampaignType) Items Enum: "giveaway" "book_club" Filter by type. Accepts single value, comma-separated values, or array syntax.
Examples: |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}| campaign_id required | integer |
| preview_id | string <uuid> Short-lived preview token generated by the CMS for this item, as carried by its preview link. Send it when fetching the item for a preview. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}| slug required | string |
| preview_id | string <uuid> Short-lived preview token generated by the CMS for this item, as carried by its preview link. Send it when fetching the item for a preview. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Returns reviews for the campaign's work written by approved campaign participants only
| campaign_id required | integer Campaign ID |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| user_id | integer >= 1 Filter records to those created by the given user ID. |
| stars | integer [ 1 .. 5 ] Filter reviews to those with exactly this many stars (1-5). |
| min_stars | integer [ 1 .. 5 ] Filter reviews to those with stars greater than or equal to this value (1-5). |
| max_stars | integer [ 1 .. 5 ] Filter reviews to those with stars less than or equal to this value (1-5). |
| sort_by | string Default: "created_at" Enum: "id" "created_at" "stars" "likes_count" "comments_count" Field to sort reviews by |
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "work_type": "book",
- "stars": 1,
- "title": "string",
- "body": "string",
- "editorial": false,
- "likes_count": 0,
- "comments_count": 0,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z",
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "work": {
- "id": 0,
- "slug": "string",
- "nstc": { },
- "title": "string",
- "subtitle": { },
- "collection_title": { },
- "collection_part_number": { },
- "series_slug": { },
- "annotation": { },
- "description": { },
- "additional_content": { },
- "bestseller_60": { },
- "imprint": { },
- "publisher": { },
- "language_code": { },
- "original_language_code": { },
- "page_count": { },
- "duration_seconds": { },
- "publication_date_first": { },
- "publication_date_latest": { },
- "expected_availability_date": { },
- "availability_status": { },
- "source": "cb",
- "cover_url": { },
- "editions": { },
- "contributors": [
- {
- "id": 0,
- "slug": "string",
- "key_names": "string",
- "names_before_key": { },
- "prefix_to_key": { },
- "contributor_role": "string"
}
], - "genres": [
- {
- "id": 0,
- "slug": "string",
- "name": "string",
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "subjects": [
- {
- "subject_code": "string",
- "scheme_identifier": "string",
- "scheme_version": { },
- "main_subject": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "campaigns": [
- {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "ratings_count": 0,
- "read_count": 0,
- "read_count_30d": 0,
- "review_count": 0,
- "favorite_count": 0,
- "article_count": 0,
- "event_count": 0,
- "reading_status_read_count": 0,
- "reading_status_reading_count": 0,
- "reading_status_want_to_read_count": 0,
- "rating_average": { },
- "ratings_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "hebban_rank": { },
- "hebban_rank_highest": { },
- "hebban_1000_rank": { },
- "sponsored_from": { },
- "sponsored_until": { },
- "is_sponsored": true,
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Submit to a campaign. This endpoint is idempotent: if the user has already submitted to this campaign, the existing submission is returned with a 200 status instead of creating a duplicate.
| campaign required | integer Campaign ID |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
required | object Flexible form data |
{- "data": { }
}{- "id": 0,
- "campaign": {
- "id": 0,
- "slug": "string",
- "type": "giveaway",
- "status": "draft",
- "campaign_status": { },
- "title": "string",
- "intro": { },
- "description": { },
- "forum_link": { },
- "hero": { },
- "work": { },
- "coordinator": { },
- "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "published_at": { },
- "scheduled_at": { },
- "starts_at": { },
- "ends_at": { },
- "submissions_count": 0,
- "rating_average": { },
- "rating_distribution": {
- "1": 0,
- "2": 0,
- "3": 0,
- "4": 0,
- "5": 0
}, - "meta_title": { },
- "meta_description": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}, - "user": {
- "id": 123,
- "name": "John Doe",
- "slug": "john-doe",
- "user_label": "normal",
- "profile_visibility": "public",
- "followers_count": 123,
- "following_count": 45,
- "reviews_count": 78,
- "challenges_count": 2,
- "reading_status_read_count": 42,
- "reading_status_reading_count": 3,
- "reading_status_want_to_read_count": 15,
- "created_at": "2024-01-15T10:30:00+00:00",
- "updated_at": "2025-01-15T10:30:00+00:00"
}, - "data": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}Lists posts for a campaign in one chronological stream, ordered by display_at (the publication date for a live post, the scheduled date for an upcoming one) with id as tiebreaker — so the intro post appears first and upcoming posts naturally follow the live ones. Every item has the same shape; upcoming posts carry upcoming: true with empty blocks (content stays private until live) and a null published_at, and their detail endpoint still returns 404 until they go live. Draft posts are never included.
| campaign_id required | integer Campaign ID |
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "campaign_id": 0,
- "title": "string",
- "upcoming": true,
- "hero_image": { },
- "blocks": [
- {
- "id": 0,
- "type": "text",
- "data": {
- "text": "string"
}, - "order": 0
}
], - "comments_closed": true,
- "comments_count": 0,
- "display_at": { },
- "published_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Returns a single live campaign post, including its content blocks.
With a valid preview_id generated for this post, for another post of its campaign or for the campaign itself, a draft or scheduled post is returned as well, including its blocks. A preview is read-only: the comments of a post that isn't live stay unavailable.
Returns 404 for a post that doesn't exist, and for a post that isn't live unless preview_id is valid for that post or its campaign. A draft or scheduled post without such a token is indistinguishable from a post that doesn't exist; an archived post is never returned.
| campaign_post_id required | integer Campaign post ID |
| preview_id | string <uuid> Short-lived preview token generated by the CMS for this post, another post of its campaign or the campaign itself. A token that has expired, or was generated for something outside this campaign, gives a 404 for a post that isn't live. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "campaign_id": 0,
- "title": "string",
- "upcoming": true,
- "hero_image": { },
- "blocks": [
- {
- "id": 0,
- "type": "text",
- "data": {
- "text": "string"
}, - "order": 0
}
], - "comments_closed": true,
- "comments_count": 0,
- "display_at": { },
- "published_at": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Returns curated editorial book lists for the app ordered by position.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "status": "draft",
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "template": { },
- "summary": { },
- "description": { },
- "hero_image": { },
- "works": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Returns curated editorial book lists for the homepage ordered by position.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "status": "draft",
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "template": { },
- "summary": { },
- "description": { },
- "hero_image": { },
- "works": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Returns curated editorial book lists for the homepage ordered by position.
Deprecated in favor of GET /curated/homepage/lists.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "status": "draft",
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "template": { },
- "summary": { },
- "description": { },
- "hero_image": { },
- "works": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
]
}Search for book lists with support for sorting and pagination
| page | integer >= 1 Default: 1 The page number for traditional pagination (used by search endpoints) |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| query required | string [ 2 .. 255 ] characters Search query (minimum 2 characters) |
| sort_by | string Default: "relevance" Enum: "relevance" "title" "created_at" "works_count" "likes_count" Field to sort results by. When |
| sort_direction | string (SortDirection) Default: "asc" Enum: "asc" "desc" Sort direction |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "status": "draft",
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "template": { },
- "summary": { },
- "description": { },
- "hero_image": { },
- "works": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "current_page": 0,
- "from": 0,
- "last_page": 0,
- "per_page": 0,
- "to": 0,
- "total": 0
}
}| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| sort_by | string Default: "created_at" Enum: "created_at" "title" "likes_count" "works_count" Field to sort results by.
|
| sort_direction | string Default: "desc" Enum: "asc" "desc" Sort direction |
| status | string Enum: "draft" "scheduled" "published" "archived" Example: status=published Filter by publication status |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "id": 0,
- "slug": "string",
- "title": "string",
- "status": "draft",
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "template": { },
- "summary": { },
- "description": { },
- "hero_image": { },
- "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}| list_id required | integer |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "title": "string",
- "status": "draft",
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "template": { },
- "summary": { },
- "description": { },
- "hero_image": { },
- "works": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}| slug required | string |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "id": 0,
- "slug": "string",
- "title": "string",
- "status": "draft",
- "published_at": { },
- "scheduled_at": { },
- "expires_at": { },
- "template": { },
- "summary": { },
- "description": { },
- "hero_image": { },
- "works": { },
- "tags": [
- {
- "id": 42,
- "name": "fiction",
- "slug": "fiction"
}
], - "likes_count": 0,
- "works_count": 0,
- "preview_works": { },
- "created_at": "2019-08-24T14:15:22Z",
- "updated_at": "2019-08-24T14:15:22Z"
}
}Returns active slides for a specific set, ordered by position.
Only returns slides where is_active is true and current date is within the active_from/active_until range. This filtering is always applied server-side and cannot be modified via query parameters.
| cursor | string Encoded cursor for cursor-based pagination |
| per_page | integer [ 1 .. 250 ] Default: 20 The number of items per page. |
| set required | string (SlideSet) Enum: "homepage" "books" "authors" "events" "reading_clubs" "theme_banner" The slide set to retrieve (e.g., homepage, books, authors) |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": [
- {
- "alt_text": "Hebban verwenst je een fijne kerstdinges!",
- "set": "homepage"
}
], - "links": {
}, - "meta": {
- "per_page": 0,
- "next_cursor": "string",
- "prev_cursor": "string"
}
}Returns public statistics about the Hebban community.
Statistics are precomputed hourly and cached. The cached_at field indicates
when the data was last calculated.
Last 30 days stats use a rolling 30-day window.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "last_30_days": {
- "new_members": 2372,
- "challenge_participants": 1161,
- "reviews": 512,
- "ratings": 2048,
- "works": 350
}, - "all_time": {
- "books_read": 8601471,
- "reviews": 377777,
- "ratings": 6625458,
- "members": 395000,
- "works": 389000,
- "book_lists": 200000
}, - "cached_at": "2025-11-28T16:00:00Z"
}
}Returns the current health status of the API and its dependencies.
This endpoint does not require authentication or the Accept: application/json header.
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "data": {
- "status": "healthy",
- "checks": {
- "property1": {
- "status": "healthy",
- "duration_ms": 12,
- "error": "Database connection failed: Connection refused"
}, - "property2": {
- "status": "healthy",
- "duration_ms": 12,
- "error": "Database connection failed: Connection refused"
}
}, - "app": {
- "version": "2.0.33",
- "environment": "production"
}
}
}Checks whether a short-lived preview_id token is currently valid. Used by the frontend before rendering previews of articles, pages, book clubs, book club posts and giveaways.
| preview_id required | string <uuid> Short-lived preview token UUID generated by Filament. |
| X-Request-Id | string^[0-7][0-9A-HJKMNP-TV-Z]{25}$ Example: 01J9Z1Q4R7Z7B4M5X6C7D8E9FA Optional client-provided correlation identifier (ULID).
|
{- "title": "Unauthenticated",
- "status": 401,
- "request_id": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "code": "auth.unauthenticated",
- "type": "about:blank",
- "detail": "Already joined this challenge.",
- "instance": "01J9Z1Q4R7Z7B4M5X6C7D8E9FA",
- "errors": {
- "property1": [
- "string"
], - "property2": [
- "string"
]
}
}