> ## Documentation Index
> Fetch the complete documentation index at: https://docs.salesive.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Read a title online

> Get the page pictures of a PDF the signed-in shopper holds, to show in an in-page reader. This is how a 30-day pass is read, since it cannot be downloaded.

The shopper's browser never receives the PDF or a link to it. The server draws each page as a JPEG with the reader's email on it, and the reader shows those pictures. Two calls make up a reader: one to open the book, one per page.

## Open the book

```http theme={null}
GET /library/read/{productId}/pages
Authorization: Bearer {{token}}
x-shop-id: {{shopId}}
```

| Parameter | Type | Description |
| - | - | - |
| `productId` | string | The `productId` of a [library](/api-reference/endpoint/library/get-library) row whose `canRead` is `true`. |

```json theme={null}
{ "data": { "pages": 46, "aspect": 1.7778, "sizes": [1000, 1600], "readOnly": true } }
```

`aspect` is width divided by height of the first page. `sizes` are the only image sizes you may ask for (the long edge, in pixels). `readOnly` is `true` for a 30-day pass or the all-access pass. The first call for a book can take a few seconds while the server fetches it.

## Get one page

```http theme={null}
GET /library/read/{productId}/page/{n}?w=1000
Authorization: Bearer {{token}}
x-shop-id: {{shopId}}
```

`n` counts from 1. `w` is one of `sizes`; any other value is refused, not rounded. The body is a JPEG (`Content-Type: image/jpeg`, `Cache-Control: private, no-store`). The page carries a footer with the reader's email, the store and a short access id, and the email is repeated faintly across the page. This works for PDFs of any size. Fetch pages with the `Authorization` header (for example with `fetch` and an object URL), because an `<img src>` cannot send it, and do not offer a save button.

## Errors

| Status | `code` | Meaning |
| - | - | - |
| `400` | `bad_page` | `n` is not a positive whole number, or `w` is not one of `sizes`. |
| `403` | `login_required` | No real signed-in account (a guest session does not count). |
| `403` | `no_access` | The shopper has no live access to this title: never bought it, the access ended or was revoked, or the title left the all-access pass. |
| `404` | `file_unavailable` | The file is missing from storage. |
| `404` | `no_such_page` | `n` is past the last page. |
| `415` | `not_readable` | The title is not a PDF, or the PDF is locked or cannot be drawn. |
| `429` | `read_limit` | A renter has used the day's page budget for this title (3 times its page count, at least 300). Try again tomorrow. Owners of a title bought outright are not limited. |
| `502` | `file_service_error` | The file service could not be reached. |
| `503` | `busy` | The server is drawing other pages. Wait the `Retry-After` seconds and try again. |

Errors are JSON. Reading a title never uses up the daily download allowance.

<Note>
  A picture someone can see can still be captured, for example with a screenshot. This removes the file, the link and the save button, and marks every page with who is reading.
</Note>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.