Skip to main content

⚠️ API in active development

The API v3 is currently in beta, if you encounter any issue or have questions, please reach out to our support team at [email protected].

Content API v3

Introduction

The Content API v3 is a lightweight, cursor-paginated feed of a store's catalog, optimized for fast, flexible, and bandwidth-efficient integrations. By combining the filter, include, and fields parameters you can shape the payload to match exactly what your integration needs:

  • Trim columnsfields=id,name,cover_url returns only three attributes per item.
  • On-demand blocksinclude=prices adds the active prices.
  • Combine bothinclude=prices,description&fields=id,name,description,prices for a compact object ready to render.

This "shape your data" approach lowers bandwidth, speeds up responses, and avoids client-side post-processing.


Authentication

HeaderExampleDescription
X-User-Tokensk_live_abc123API-Key generated in your dashboard. Only accepts tokens via header for security.

All requests must be performed over HTTPS.


Additional metadata

When requested with include=metadata, the response can include richer metadata to improve discovery and filtering:

  • publisher: list of publisher names
  • author: list of author names
  • bisac: array of objects with code and localized label (full BISAC path)
  • keywords: array of keyword strings for content tagging and discovery
  • metrics: object with total_pages, total_words, and total_seconds for content metrics

These metadata fields are also controlled by the fields parameter. When you include metadata, you can select only specific metadata keys (alongside any core fields) to keep responses compact. For example:

GET /api/v3/content?include=metadata&fields=id,name,author,bisac

Endpoint

GET /api/v3/content

Query Parameters

ParameterTypeDescription
per_pageintegerItems per page (1-500, default 100).
cursorstringCursor token returned by links.next / links.prev.
includestringComma-separated includes: prices, description, metadata.
fieldsstringComma-separated list of fields to return.
filter[query]stringSearch by title/name.
filter[external_id]stringExact match search by external_id/ISBN-13.
filter[updated_at][from]datetimeIncremental sync. Start date (YYYY-MM-DD HH:mm:ss). Must be within the last month.
filter[updated_at][to]datetimeEnd date (YYYY-MM-DD HH:mm:ss). ≤ 1 month after from, cannot be in the future.
filter[created_at][from]datetimeStart date (any past date, YYYY-MM-DD HH:mm:ss).
filter[created_at][to]datetimeEnd date. Range between from and to must not exceed 1 month, cannot be in the future.
sortstringSort field: created_at, updated_at. Prefix with - for descending order.

Shaping the response

Use these two parameters together to get only what you need:

  • include – adds extra blocks (prices, description).
  • fields – trims the attributes returned.

Example – Get only ID, name and prices:

GET /api/v3/content?include=prices&fields=id,name,prices

Date filters

Incremental synchronization (updated_at)

Pull only the items that changed since your last import.

  • from and to must both be within the last month.
  • The span between them must not exceed 1 month.

Example – content updated in the last 7 days:

GET /api/v3/content?filter[updated_at][from]=2024-12-25 00:00:00&filter[updated_at][to]=2024-12-31 23:59:59

created_at filters follow the same 1-month span rule, but from/to can point to any past date (future dates are rejected).

All dates must use the YYYY-MM-DD HH:mm:ss format.

Sorting

Results are sorted by publication date (published_at) descending by default.

If you need a different order you can use the sort parameter (prefix with - for descending):

Allowed fields: created_at, updated_at.

Examples:

# Newest updated first
GET /api/v3/content?sort=-updated_at

# Oldest items first (by creation date)
GET /api/v3/content?sort=created_at

Combining filters and sorting

GET /api/v3/content?filter[created_at][from]=2024-01-01 00:00:00&sort=-updated_at&include=prices&fields=id,name,created_at,updated_at

Response Structure

Core object (always present):

{
"id": 468166,
"external_id": "9781496822482",
"name": "Conversations with Donald Hall",
"slug": "conversations-with-donald-hall",
"lang": "en",
"file_type": "epub",
"cover_url": "https://.../468166.jpg",
"reader_url": "https://.../read/...",
"product_url": "https://.../book/...",
"created_at": "2021-03-19T00:00:00Z",
"published_at": "2019-09-13T00:00:00Z",
"license": "retail",
"free": {
"enabled": false,
"until": "2025-12-12T00:00:00Z",
"require_login": false
},
"preview": {
"enabled": true,
"require_login": false
}
}

Optional Includes

When requested via include parameter:

Prices Block

{
"prices": [
{
"currency_id": "USD",
"amount": 9.99
},
{
"currency_id": "EUR",
"amount": 8.50
}
]
}

Description Block

{
"description": "A comprehensive collection of interviews with Donald Hall..."
}

Metadata Block

Returned when include=metadata is present. Example (subset):

{
"publisher": ["Vintage"],
"author": ["Jane Doe"],
"bisac": [
{ "code": "FIC019000", "label": "Fiction > Literary" },
{ "code": "FIC000000", "label": "Fiction > General" }
],
"keywords": ["fiction", "literary", "contemporary"],
"metrics": {
"total_pages": 320,
"total_words": 85000,
"total_seconds": 0
}
}

Response Wrapper

{
"data": [ /* core ± extras */ ],
"links": {
"next": "https://.../content?cursor=abc123&per_page=100",
"prev": null
},
"meta": {
"has_more": true
}
}

Field Reference

Core Fields

FieldTypeDescription
idintegerUnique issue identifier
external_idstringISBN-13 or external reference
namestringPublication title
slugstringURL-friendly identifier
langstringLanguage code
file_typestringContent type: pdf, epub, audio, physical
audiencestringTarget audience
cover_urlstringCover image URL
reader_urlstringDirect reader link
product_urlstringStorefront product page
created_atstringIssue creation date (ISO 8601)
published_atstringPublication date (ISO 8601)
licensestringLicense type: retail, ppu, shared, owner
freeobjectFree access information
previewobjectPreview access information

Free Access Object

FieldTypeDescription
enabledbooleanWhether free access is available
untilstringFree access expiration date
require_loginbooleanWhether login is required for free access

Preview Object

FieldTypeDescription
enabledbooleanWhether preview is available
require_loginbooleanWhether login is required for preview

Pagination Workflow

  1. Perform the initial request without cursor.
  2. Store the links.next token (if any) and display the current page.
  3. To fetch the next batch, send cursor=<token>.
  4. Continue until links.next is null or meta.has_more is false.
Best practice

Always rely on meta.has_more rather than counting items to detect the end of the catalog.


Error Handling

Validation Errors (422)

Invalid parameters return 422 Unprocessable Entity:

{
"message": "The given data was invalid.",
"errors": {
"filter.unknown_key": ["The selected filter.unknown_key is invalid."],
"filter.created_at.from": ["The filter.created_at.from field must match the format Y-m-d H:i:s."],
"filter.updated_at.to": ["The filter.updated_at.to field must match the format Y-m-d H:i:s."],
"per_page": ["The per page must be between 1 and 500."]
}
}

Invalid Includes (422)

Invalid include parameters return 422 Unprocessable Entity:

{
"message": "Requested include(s) are not allowed. Allowed include(s) are: prices, description"
}

Authentication Errors (401)

Missing or invalid authentication:

{
"message": "Unauthenticated."
}

Examples

Minimal request

GET /api/v3/content?filter[query]=harry&per_page=100 HTTP/1.1
Host: {store_final_domain}
X-User-Token: sk_live_xxx

Selective fields and includes

GET /api/v3/content?include=prices,description&fields=id,name,description,prices&per_page=100 HTTP/1.1
Host: {store_final_domain}
X-User-Token: sk_live_xxx

Filter by creation date range

GET /api/v3/content?filter[created_at][from]=2024-01-01 00:00:00&filter[created_at][to]=2024-12-31 23:59:59&sort=-created_at HTTP/1.1
Host: {store_final_domain}
X-User-Token: sk_live_xxx

Filter by update date and sort by newest first

GET /api/v3/content?filter[updated_at][from]=2024-06-01 00:00:00&sort=-updated_at&include=prices&fields=id,name,updated_at,prices HTTP/1.1
Host: {store_final_domain}
X-User-Token: sk_live_xxx

Search by ISBN

GET /api/v3/content?filter[external_id]=9781496822482 HTTP/1.1
Host: {store_final_domain}
X-User-Token: sk_live_xxx

OpenAPI Specification

Download the machine-readable contract: content_v3.yml.


See Also

X

Graph View