⚠️ 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_url
returns only three attributes per item. - On-demand blocks –
include=prices
adds the active prices. - Combine both –
include=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
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
code
and localizedlabel
(full BISAC path) - keywords: array of keyword strings for content tagging and discovery
- metrics: object with
total_pages
,total_words
, andtotal_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
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 . |
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.
from
andto
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
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.next
token (if any) and display the current page. - To fetch the next batch, send
cursor=<token>
. - Continue until
links.next
isnull
ormeta.has_more
isfalse
.
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.