⚠️ 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 columns –
fields=id,name,cover_urlreturns only three attributes per item. - On-demand blocks –
include=pricesadds the active prices. - Combine both –
include=prices,description&fields=id,name,description,pricesfor a compact object ready to render.
This "shape your data" approach lowers bandwidth, speeds up responses, and avoids client-side post-processing.
Authentication
| Header | Example | Description |
|---|---|---|
| X-User-Token | sk_live_abc123 | API-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
codeand localizedlabel(full BISAC path) - keywords: array of keyword strings for content tagging and discovery
- metrics: object with
total_pages,total_words, andtotal_secondsfor 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
| Parameter | Type | Description |
|---|---|---|
per_page | integer | Items per page (1-500, default 100). |
cursor | string | Cursor token returned by links.next / links.prev. |
include | string | Comma-separated includes: prices, description, metadata, geographic_restrictions. |
fields | string | Comma-separated list of fields to return. |
filter[query] | string | Search by title/name. |
filter[external_id] | string | Exact match search by external_id/ISBN-13. |
filter[updated_at][from] | datetime | Incremental sync. Start date (YYYY-MM-DD HH:mm:ss). Must be within the last month. |
filter[updated_at][to] | datetime | End date (YYYY-MM-DD HH:mm:ss). ≤ 1 month after from, cannot be in the future. |
filter[created_at][from] | datetime | Start date (any past date, YYYY-MM-DD HH:mm:ss). |
filter[created_at][to] | datetime | End date. Range between from and to must not exceed 1 month, cannot be in the future. |
sort | string | Sort 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.
fromandtomust 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..."
}
Geographic Restrictions Block
Returned when include=geographic_restrictions is present. This block indicates which countries can sell or access the content based on territorial rights.
Possible Values:
null: No restrictions, content is available worldwide- Object with
includedandexcludedarrays: Territorial rights information- Whitelist:
includedcontains country codes,excludedis empty - Blacklist:
includedcontains['WORLD'],excludedcontains restricted countries
- Whitelist:
Examples:
No restrictions (worldwide):
{
"geographic_restrictions": null
}
Whitelist (available only in specific countries):
{
"geographic_restrictions": {
"included": ["AR", "CL", "UY"],
"excluded": []
}
}
Blacklist (worldwide except specific countries):
{
"geographic_restrictions": {
"included": ["WORLD"],
"excluded": ["US", "CA"]
}
}
Use Cases:
- Bookshops can determine which marketplace content they can legally sell in their territory
- External sales reporting can be validated against territorial rights
- Content discovery can be filtered based on geographic availability
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
| Field | Type | Description |
|---|---|---|
id | integer | Unique issue identifier |
external_id | string | ISBN-13 or external reference |
name | string | Publication title |
slug | string | URL-friendly identifier |
lang | string | Language code |
file_type | string | Content type: pdf, epub, audio, physical |
audience | string | Target audience |
cover_url | string | Cover image URL |
reader_url | string | Direct reader link |
product_url | string | Storefront product page |
created_at | string | Issue creation date (ISO 8601) |
published_at | string | Publication date (ISO 8601) |
license | string | License type: retail, ppu, shared, owner |
free | object | Free access information |
preview | object | Preview access information |
Free Access Object
| Field | Type | Description |
|---|---|---|
enabled | boolean | Whether free access is available |
until | string | Free access expiration date |
require_login | boolean | Whether login is required for free access |
Preview Object
| Field | Type | Description |
|---|---|---|
enabled | boolean | Whether preview is available |
require_login | boolean | Whether login is required for preview |
Pagination Workflow
- Perform the initial request without
cursor. - Store the
links.nexttoken (if any) and display the current page. - To fetch the next batch, send
cursor=<token>. - Continue until
links.nextisnullormeta.has_moreisfalse.
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, metadata, geographic_restrictions"
}
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
Get geographic restrictions for marketplace content
GET /api/v3/content?include=geographic_restrictions&fields=id,name,geographic_restrictions HTTP/1.1
Host: {store_final_domain}
X-User-Token: sk_live_xxx
Response example:
{
"data": [
{
"id": 468166,
"name": "Conversations with Donald Hall",
"geographic_restrictions": {
"included": ["US", "CA", "MX"],
"excluded": []
}
}
],
"links": {
"next": "...",
"prev": null
},
"meta": {
"has_more": true
}
}
OpenAPI Specification
Download the machine-readable contract: content_v3.yml.