Skip to main content

Migration Guide: Content API v1 → v3

This document compares Content API v1 and v3 and provides a practical migration guide for integrators. The v3 feed is designed for speed, bandwidth efficiency, and flexibility via cursor pagination and response shaping (fields and includes).

Related Documentation:

Endpoint Mapping

Content CRUD

Operationv1 Endpointv3 Endpoint
ListGET /integration-api/v1/dashboard/issuesGET /api/v3/content
Get singleGET /integration-api/v1/dashboard/issues/{id}GET /api/v3/content/{id}
CreatePOST /integration-api/v1/dashboard/issuesPOST /api/v3/content
Bulk createN/APOST /api/v3/content/bulk
UpdatePUT /integration-api/v1/dashboard/issues/{id}PUT /api/v3/content/{id}
DeleteDELETE /integration-api/v1/dashboard/issues/{id}DELETE /api/v3/content/{id}

Audiobook Tracks

Operationv1 Endpointv3 Endpoint
List tracksGET /integration-api/v1/dashboard/issues/{id}/tracksGET /api/v3/content/{id}/tracks
Add trackPOST /integration-api/v1/dashboard/issues/{id}/tracksPOST /api/v3/content/{id}/tracks
Update trackPUT /integration-api/v1/dashboard/issues/{id}/tracks/{track}PUT /api/v3/content/{id}/tracks/{track}
Reorder tracksPUT /integration-api/v1/dashboard/issues/{id}/tracks-ordersPUT /api/v3/content/{id}/tracks/order
Delete trackDELETE /integration-api/v1/dashboard/issues/{id}/tracks/{track}DELETE /api/v3/content/{id}/tracks/{track}

At-a-Glance Comparison

Topicv1v3
Base path/integration-api/v1/dashboard/issues/api/v3/content
AuthAPI token in query stringAPI token in X-User-Token header or request body (no query string)
PaginationPage-based paginator (page, last_page, etc.)Cursor pagination with links.next/links.prev and meta.has_more
Search/filterOverloaded query param (state, name, id)Structured filters: filter[query], filter[external_id], filter[created_at], filter[updated_at]
Date filtersN/AStrict ranges, 1-month span rules, format YYYY-MM-DD HH:mm:ss
SortingNot standardizedsort on created_at/updated_at
ShapingNot supportedinclude blocks (prices, description, metadata) + fields selection
Prices shapeObject keyed by currency (e.g., { "USD": 25 })Array of objects ([{ "currency_id": "USD", "amount": 25 }])
TimestampsMixed structures (e.g., published_at.timestamp + date)ISO 8601 strings (e.g., published_at: "2019-09-13T00:00:00Z")
Cover URLcover_image_pathcover_url
Error handlingJSON with CODE and payloadSame CODE with improved message

Breaking Changes for Integrators

  1. Endpoint change: GET /integration-api/v1/dashboard/issuesGET /api/v3/content.
  2. Pagination: switch from page-based to cursor-based.
    • No numeric page parameter.
    • Use links.next token and check meta.has_more.
  3. Filters: the overloaded query parameter is deprecated in v3.
    • Use filter[query] for free-text search by title/name.
    • Use filter[external_id] for exact ISBN/external ID matches.
    • Use filter[updated_at][from|to] or filter[created_at][from|to] with strict 1-month span rules and YYYY-MM-DD HH:mm:ss format.
  4. Sorting: v3 introduces sort with allowed fields created_at, updated_at (prefix with - for descending).
  5. Response shaping:
    • Use include=prices,description,metadata to request optional blocks.
    • Use fields= to trim the returned attributes for bandwidth efficiency.
  6. Schema differences:
    • cover_image_path (v1) → cover_url (v3).
    • published_at structure (v1 object) → ISO 8601 string (v3).
    • prices (v1 object by currency) → prices (v3 array of {currency_id, amount}).
    • free (v1 boolean) → free (v3 object: {enabled, until, require_login}).
    • New optional blocks: description, metadata (with publisher, author, bisac, keywords, country, edition, narrator, category, collection, metrics), geographic_restrictions.
  7. Validation: invalid includes or parameters return 422 with detailed error messages in v3.

Response Differences

v1 (example excerpt)

{
"CODE": "success",
"data": {
"paginator": {
"current_page": 1,
"data": [
{
"id": 468166,
"external_id": "9781496822482",
"name": "Conversations with Donald Hall",
"cover_image_path": "https://.../cover.jpg",
"free": false,
"prices": { "USD": 25 }
}
],
"last_page": 6
}
}
}

v3 (example excerpt)

{
"data": [
{
"id": "468166",
"external_id": "9781496822482",
"name": "Conversations with Donald Hall",
"file_type": "epub",
"cover_url": "https://.../468166.jpg",
"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 }
}
],
"links": {
"next": "https://.../content?cursor=abc123&per_page=100",
"prev": null
},
"meta": { "has_more": true }
}

Prices shape

// v1
{"prices": {"USD": 9.99, "EUR": 8.50}}

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

Migration Checklist

  1. Authentication
    • Keep using your store API token.
    • For v3, send it in the X-User-Token header over HTTPS.
  2. Endpoints
    • Replace v1 listing endpoint with GET /api/v3/content.
  3. Pagination
    • Implement cursor pagination.
    • Use links.next for the next request and meta.has_more to detect completion.
  4. Filters
    • Replace query with filter[query].
    • Use filter[external_id] for ISBN/external ID lookups.
    • Add date-windowed sync via filter[updated_at] or filter[created_at] with the 1‑month rules.
  5. Sorting
    • Add sort when you need ordering other than the default (published_at desc).
  6. Response shaping
    • Add include= for optional blocks (prices, description, metadata).
    • Trim with fields= to reduce payloads.
  7. Schema updates
    • Map cover_image_pathcover_url.
    • Map prices object → prices array.
    • Update timestamp parsing to ISO 8601 strings.
    • Handle free and preview objects.
  8. Error handling
    • Handle 422 validation errors (e.g., invalid includes, date formats, ranges) and 401 for auth.
  9. Rollout
    • Run v1 and v3 in parallel behind a feature flag.
    • Monitor logs and payload sizes; switch traffic when stable.

Practical Examples

Minimal listing with search (v3)

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

Incremental sync by update date (v3)

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

Shape response with fields and includes (v3)

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

Fetch by ISBN/external_id (v3)

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

Troubleshooting FAQ

How do I request a single item in v3? Use GET /api/v3/content/{id} for direct lookup. Supports both internal and external IDs via the id_type parameter.

What's the difference between filter[external_id] and id_type=external?

  • filter[external_id] on list endpoint returns items matching that ID
  • id_type=external on single-item endpoints (GET, PUT, DELETE) allows using external ID in the path

What page size should I use? v3 supports per_page from 1 to 500 (default 100). Use higher values for faster syncs when appropriate.

Why am I getting a 422 error? Check date formats/ranges, allowed includes (prices, description, metadata, geographic_restrictions), and per_page bounds.

Do I have to include metadata? No. Only request include=metadata when you need it. Trim with fields to keep responses small.

How do I migrate bulk imports to v3? Use POST /api/v3/content/bulk with up to 100 items per request. The response includes partial success handling with detailed errors for any failed items.

Can I still use the old v1 endpoints? Yes, v1 endpoints remain available during the migration period. We recommend starting with v3 for new integrations.

What about audiobook track endpoints? Track endpoints have moved from /issues/{id}/tracks-orders to /content/{id}/tracks/order. The structure is otherwise similar.


See Also


X

Graph View