Skip to main content

Lists API

Read the reading lists of any user of your store, and manage the publications they hold, from your own platform.

This is an administrator API: every endpoint operates on another user's data, identified by the target user parameters described below. There is no self-service mode.

Features

  • Read any list of any user of your store, favorites and named lists, private ones included
  • Read the publications a list holds, with the publica.la id, the ISBN and the reader URL of each one
  • Add and remove publications in any list of a user, favorites included, addressed by internal id or by ISBN
  • Idempotent writes: replaying a call never undoes what the previous one did
  • Cursor-based pagination on every collection

Authentication

HeaderExampleDescription
X-User-Tokenapi-abc123...API token generated in your dashboard. Header-only for security.

All requests must be performed over HTTPS. The token is not accepted as a query parameter or in the request body.

curl -X GET "https://yourstore.publica.la/api/v3/lists?user_external_id=student-1042" \
-H "X-User-Token: api-abc123..." \
-H "Accept: application/json"

The token must belong to an administrator

Unlike the rest of the v3 API, where the token itself is the authorization, the Lists API also checks the role of the user who owns the token. The token must belong to a store administrator, because these endpoints read and write other users' data.

A token that belongs to a regular user is rejected on every endpoint of this resource:

{
"message": "This token cannot operate on other users' lists."
}

The store also needs the integrations API enabled. If it is not, every endpoint of this resource answers:

{
"message": "This store cannot access the integrations API."
}

Both responses use status 403. Contact support if your store needs the integrations API enabled.


Identifying the target user

Every endpoint requires exactly one of these parameters. Send them in the query string on GET and DELETE, and in the JSON body on POST.

ParameterTypeDescription
user_external_idstringYour own identifier for the user, the one you send as external_id when the account is provisioned
user_emailstringEmail address of the user in your store
  • Sending neither returns 422.
  • Sending both returns 422.
  • A user who does not exist in the store, or whose account was deactivated, returns 404 with The specified user does not exist in this store.
The account is never created

This API never provisions the user it was pointed at. An unknown identifier is an error, not an invitation to create the account. Use the Users API or the Auth Token integration to create accounts.

The user is required even when a list is addressed by its id: a list is only reachable through the user it belongs to, so an id that is not one of that user's lists is a 404.


Addressing a list

Every endpoint under /api/v3/lists/{list} accepts two forms of {list}, both resolved among the target user's lists:

FormExampleDescription
SlugfavoritesThe user's default list of that kind. No prior lookup needed
List id9f2d4b1e-6c3a-4f58-9b77-1d0a2e5c8b34Any list of the user, as returned by the list index

Default lists have a fixed slug. The only one exposed today is favorites. Custom lists carry the name the user gave them, so they are addressed by id only.

# The favorites of a user, without knowing the list id
GET /api/v3/lists/favorites/items?user_external_id=student-1042

# A custom list of the same user, by id
GET /api/v3/lists/9f2d4b1e-6c3a-4f58-9b77-1d0a2e5c8b34/items?user_external_id=student-1042

An id that is not a list of the target user, a slug other than favorites, or a reserved storefront collection returns 404 with Not found.


Identifying the publication

The item write endpoints address a publication with content_id plus an optional id_type.

ParameterTypeDefaultDescription
content_idstring(required)The publication identifier, read according to id_type
id_typestringinternalinternal reads content_id as the publica.la id; external reads it as one of the publication identifiers (ISBN among them)
  • Any other value of id_type returns 422.
  • The two modes are exclusive: with id_type=external, a publica.la id is not accepted and returns 404.
  • A publication that does not exist, belongs to another store, or is no longer available in your store, returns 404 with The specified publication does not exist in this store.

Only publications are addressable. Subscription plans, which a user can also add to a list from the storefront, are outside the scope of this API.


API Endpoints

OperationMethodEndpointDescription
List a user's listsGET/api/v3/listsEvery list the store shows the target user, filterable by type, id or name
Get list itemsGET/api/v3/lists/{list}/itemsThe publications a list holds
Add an itemPOST/api/v3/lists/{list}/itemsAdd a publication to a list of the user
Remove an itemDELETE/api/v3/lists/{list}/items/{content_id}Remove a publication from a list of the user

{list} is a slug or a list id, see Addressing a list. Every endpoint takes the target user parameters.


List management is not available through the API

This API reads lists and writes their contents. It does not manage lists themselves. The following operations exist only in the storefront, where the owner of the list performs them, and have no endpoint in the API:

OperationAvailable in the API
Create a named listNo
Rename a listNo
Change a list between public and privateNo
Delete a listNo
Add, remove or change collaborators on a listNo

The favorites list is the exception: it is created on first use by POST /api/v3/lists/favorites/items, so no create operation is needed for it.


List types

typenameAddressable byDescription
favoritesfavoritesThe favorites slug, or its idThe single favorites list of the user, created on first use
customThe name the user gaveIts id onlyA named list the user created in the storefront, public or private

The shopping cart and the save-for-later list are reserved storefront collections and are not part of this API. They never appear in the list index, and addressing one by its id returns 404.

Private lists are visible to an administrator token: reading them is the purpose of this API.


Cursor pagination

Every collection endpoint pages by cursor:

{
"data": [],
"links": {
"next": "https://yourstore.publica.la/api/v3/lists?user_external_id=student-1042&cursor=eyJsaXN0cy5pZCI6MTQ...",
"prev": null
},
"meta": {
"has_more": true
}
}
ParameterTypeDefaultDescription
per_pageinteger100Items per page, between 1 and 500
cursorstring-Cursor token, taken from links.next

Pagination workflow

  1. Make the initial request without cursor.
  2. Follow links.next as-is: it already carries your other parameters.
  3. Continue until meta.has_more is false.
Best Practice

Use meta.has_more to detect the end of the results. These responses carry no total count.


Common response format

List object

{
"data": {
"id": "9f2d4b1e-6c3a-4f58-9b77-1d0a2e5c8b34",
"name": "favorites",
"type": "favorites",
"private": false,
"role": "owner"
}
}
FieldTypeDescription
idstringStable id of the list, used in the list endpoints
namestringfavorites for the favorites list, the user's own name for a named list
typestringfavorites or custom
privatebooleantrue when the list is not visible to other users in the storefront
rolestringThe target user's role on the list: owner, editor or viewer

Lists carry no timestamps of their own, so no creation date is exposed.

A user's lists include the ones they were invited to as a collaborator. role tells the two apart: owner for the lists the user created, editor or viewer for lists someone else shared with them. The favorites list is always owner.

List item object

{
"data": {
"content_id": "468166",
"isbn": "9781234567890",
"title": "Conversations with Donald Hall",
"reader_url": "https://yourstore.publica.la/reader/conversations-with-donald-hall",
"added_at": "2026-08-27T12:00:00.000000Z"
}
}
FieldTypeDescription
content_idstringpublica.la id of the publication
isbnstring or nullPrimary identifier of the publication, null when it has none
titlestringTitle of the publication
reader_urlstringURL that opens the publication in the reader
added_atstring or nullISO 8601 timestamp of when the publication was added to the list, null for publications added before the platform started recording it

The items endpoints return items in a stable order, the same order on every request, so a cursor pages through a list without repeating or skipping an item. That order is not chronological.


Error handling

StatusMessageCause
401Unauthenticated.Missing or invalid X-User-Token
403This store cannot access the integrations API.The store does not have the integrations API enabled
403This token cannot operate on other users' lists.The token does not belong to a store administrator
404The specified user does not exist in this store.No user matches user_external_id or user_email, or the account was deactivated
404The specified publication does not exist in this store.No publication matches content_id under the given id_type
404Not foundA list id that is not one of the target user's lists, an unknown slug, or a reserved storefront collection (cart, save for later)
422First validation errorMissing, duplicated or invalid parameters
429Too Many RequestsRate limit or daily read quota exceeded

Authentication error (401)

{
"message": "Unauthenticated."
}

Validation error (422)

The message repeats the first error; errors carries all of them, keyed by parameter.

{
"message": "The user external id field is required when user email is not present.",
"errors": {
"user_external_id": [
"The user external id field is required when user email is not present."
],
"user_email": [
"The user email field is required when user external id is not present."
]
}
}

Sending both identifiers at once:

{
"message": "The user external id field prohibits user email from being present.",
"errors": {
"user_external_id": [
"The user external id field prohibits user email from being present."
]
}
}

Not found (404)

{
"message": "The specified user does not exist in this store."
}

Request logging

Every call to this resource is recorded in your store's API log, with the token that made the call, the endpoint and method, the response status, and the parameters sent (the target user among them). Logs are retained for 6 months.


Rate limiting

Two limits apply: a per-token burst of 60 requests per minute and a daily read quota of 2,000 reads per token plus 5,000 per store (GET and HEAD only; writes are not counted). Exceeding either returns 429 Too Many Requests with a Retry-After header.

Reading a user's favorites on every page view of your own platform exhausts the daily quota quickly. Read the list once per session and cache it on your side. See the API Overview for full details.


Quick start examples

Read a user's lists

curl -X GET "https://yourstore.publica.la/api/v3/lists?user_external_id=student-1042" \
-H "X-User-Token: your-api-token" \
-H "Accept: application/json"

Add a publication to a user's favorites by ISBN

curl -X POST "https://yourstore.publica.la/api/v3/lists/favorites/items" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"user_external_id": "student-1042",
"content_id": "9781234567890",
"id_type": "external"
}'

Next steps


See also

X

Graph View