API reference
Books
Books built from collections, and the epub they compile to.
Paths below are relative to
https://recipejam.com/api/v1
/books
List books
Books you have made, most recently changed first.
Parameters
| Field | Type | Notes |
|---|---|---|
perPage
|
integer · query | 1 to 100. Defaults to 25. |
page
|
integer · query | Which page, from 1. |
since
|
string · query | An ISO 8601 timestamp. Returns only what has changed since then, deleted records included, so a synced device can catch up without refetching everything. Url-encode it — a raw `+` in a query string arrives as a space. |
deleted
|
string · query | `only` lists the wastebasket — what was deleted and can still be restored, each with a `deletedAt`. `include` lists both. Left out, you get the ordinary listing. |
Response
200
with a page of Book objects in the pagination envelope.
/books
Make a book from a collection
Binds a collection into a book: cover, page layout and — unless you say otherwise — the compiled epub, in one call.
Request body
| Field | Type | Notes |
|---|---|---|
collectionId
required
|
string | The collection to bind. It must be one you can see, and it must have recipes in it. |
name
|
string max 255 | A title of its own. Defaults to the collection's name. |
coverTemplate
|
string banner, ribbon, plate | How the title sits on the cover. Defaults to `banner`. A cover is only drawn when the collection or one of its recipes has a photograph. |
separatePages
|
boolean | A page per recipe. Defaults to true; false runs them on. |
compile
|
boolean | Build the epub now. Defaults to true, which adds seconds to the request. Send false to lay the book out and compile it later. |
Example request body
{
"collectionId": "04857llp3g",
"name": "What We Ate That Year",
"coverTemplate": "ribbon"
}
Response
201
with a single Book object under a `data` key.
- There is no way to assemble a book page by page. The layout rules live in one place, and a second way of expressing them would be a second way of getting them wrong.
- A collection with no recipes in it comes back 422, saying so.
- You can bind a collection somebody shared with you. The book is yours, not theirs.
- With `compile` false the book answers with `needsCompile: true` and downloading it is a 404 until you compile it.
/books/{book}
Get a book
One book, with its page count and cover.
Parameters
| Field | Type | Notes |
|---|---|---|
book
|
string · path | The book id. |
Response
200
with a single Book object under a `data` key.
/books/{book}
PUT
Update a book
Rename it, re-credit it, publish it, or point its QR code at a shop. Not the contents — those come from the collection it was bound from.
Parameters
| Field | Type | Notes |
|---|---|---|
book
|
string · path | The book to change. |
Request body
| Field | Type | Notes |
|---|---|---|
name
|
string max 255 | A new title. |
isPublic
|
boolean | True gives the book a public link that anyone can read and download. |
tags
|
array of string | Replaces the whole tag list. |
author
|
string, or null max 255 | Who it is credited to on the cover. Merged into `metadata`, so it does not disturb the by-line. |
byLine
|
string, or null max 500 | The line under the title. |
storeUrl
|
string, or null http or https | Where the book is sold. Checked rather than trusted — a code printed on a cover cannot be corrected later. |
qrTarget
|
string share or store | What the book's QR code points at. |
Example request body
{
"name": "What We Ate That Year",
"author": "The Bird Family",
"isPublic": true
}
Response
200
with a single Book object under a `data` key.
- Renaming does not rebuild the epub. The file keeps the old title inside it until you compile again — `needsCompile` says when that is owed.
- There is no DELETE for books yet.
/books/{book}
Delete a book
Moves it to the bin, with the pages arranged in it. Recoverable for 30 days.
Parameters
| Field | Type | Notes |
|---|---|---|
book
|
string · path | The book to delete. |
Response
204
with an empty body.
- Nothing else goes with it. The recipes and the collections it was built from are untouched — which is why this is allowed where deleting a collection with recipes in it is refused.
- The compiled epub stays on disk until the window closes, so a restored book is downloadable again without a rebuild.
- A book shared with you can be read, never deleted. That comes back 403.
/books/{book}/restore
Restore a book
Takes one back out of the bin, with its pages and its cover.
Parameters
| Field | Type | Notes |
|---|---|---|
book
|
string · path | The deleted book. Find it with `deleted=only`. |
Response
200
with a single Book object under a `data` key.
- Past the retention window this answers 404.
/books/{book}/compile
Compile a book
Builds the epub from the book's current contents. Synchronous, and slow enough to matter — seconds, not milliseconds.
Parameters
| Field | Type | Notes |
|---|---|---|
book
|
string · path | The book to build. |
Response
200
with a single Book object under a `data` key.
- Compiling counts as editing, not reading: a viewer cannot trigger it, and it comes back 403 for them.
- A build that fails answers 422 with the reason, rather than 500.
- Check `needsCompile` first. Compiling a book that does not need it costs the same and changes nothing.
- `needsCompile` now tracks the contents too: editing a recipe or a collection inside the book marks it, not only changing the book itself.
/books/{book}/pages
Read a book's pages
Every page in reading order, with whether a layout rebuild will replace it.
Parameters
| Field | Type | Notes |
|---|---|---|
book
|
string · path | The book. |
Response
200
with the page objects under a `data` key. No pagination on this one.
/books/{book}/pages
Place a page
Put a divider, a picture, a note, a single recipe or another collection into a book. A page placed this way survives every later rebuild of the layout.
Parameters
| Field | Type | Notes |
|---|---|---|
book
|
string · path | The book to place it in. |
Request body
| Field | Type | Notes |
|---|---|---|
type
required
|
string divider, picture, note, recipe, collection | Cover, title and contents belong to the layout and are refused here — there is exactly one of each and the layout owns them. |
heading
|
string max 255 | The section name on a divider, the title on a note. |
body
|
string max 5000 | The words on a note. Blank lines become paragraphs. |
caption
|
string max 255 | The line under a picture. |
imageId
|
string | The photograph. Required for a picture page, optional as a divider background. |
recipeId
|
string | Required for a recipe page. |
collectionId
|
string | Required for a collection page. A book may hold more than one. |
position
|
integer | Where it goes, counting from 1. Defaults to the end; everything at or after it shifts down. |
Example request body
{
"type": "divider",
"heading": "Puddings",
"position": 4
}
Response
201
with a single page object under a `data` key.
- Fields the type does not render are dropped rather than stored, so a caption cannot end up on a note where nothing will ever show it.
- Anything that is not yours — a photograph, a recipe, a collection — answers 404 rather than 403, the same as one that does not exist.
- The book is left with unpublished changes. Compile it to publish them.
/books/{book}/pages/{page}
PUT
Change or move a page
Edit the words on a page, swap its photograph, or move it somewhere else in the book.
Parameters
| Field | Type | Notes |
|---|---|---|
book
|
string · path | The book. |
page
|
string · path | The page to change. |
Request body
| Field | Type | Notes |
|---|---|---|
heading
|
string | A new heading. |
body
|
string | New words on a note. |
caption
|
string | A new caption. |
imageId
|
string, or null | A different photograph. Null takes it away. |
position
|
integer | Move it. Counting from 1. |
Example request body
{
"position": 1
}
Response
200
with a single page object under a `data` key.
/books/{book}/pages/{page}
Take a page out
Removes it from the book. Nothing else is deleted — a recipe page removed here leaves the recipe alone.
Parameters
| Field | Type | Notes |
|---|---|---|
book
|
string · path | The book. |
page
|
string · path | The page to remove. |
Response
204
with an empty body.
- A generated page can be removed too, and comes back the next time the layout is rebuilt. That is the honest behaviour rather than a refusal.
/books/{book}/download
Download the epub
The compiled file, as application/epub+zip. Not JSON.
Parameters
| Field | Type | Notes |
|---|---|---|
book
|
string · path | The book to download. |
Response
200
with the file itself, as application/epub+zip. This one is not JSON.
- 404 when the book has never been compiled. Compile it first.
- This endpoint always needs a token, published or not. Publishing a book gives it a public web link instead — /b/{id} to read, and a download from there — which is the one to hand to somebody without an account.
Try these
The endpoints on this page, sent from your browser with your own token. Nothing is proxied through us.
Kept in this browser only, so it survives a reload. It is never sent to RecipeJam except as the header on the request you ask for.
The same request, as curl
The book object
| Field | Type | Notes |
|---|---|---|
id
|
string | Opaque identifier. |
name
|
string | The book's title. |
isPublic
|
boolean | Whether the book answers on its public link, and whether it can be downloaded without an account. |
tags
|
array of string | Short labels. |
metadata
|
object | `author` and `byLine`, as they appear on the cover. |
needsCompile
|
boolean | True when the contents have changed since the epub was last built. The file, if any, is out of date. |
compiledAt
|
string, or null | When the epub was last built. Null means never. |
pageCount
|
integer | How many pages the book holds — recipes, collection pages and dividers together. |
coverImage
|
image, or absent | Only when the book has one. |
createdAt
|
string | ISO 8601. |
updatedAt
|
string | ISO 8601. |
A page
A book is a list of these. Most are laid out from a collection and are replaced whenever the layout is rebuilt; the ones somebody placed survive it — which is what `placed` tells you.
| Field | Type | Notes |
|---|---|---|
id
|
string | Opaque identifier. |
type
|
string | cover, title, toc, collection, recipe, picture, note or divider. |
position
|
integer | Where it sits in the book, from 1. |
placed
|
boolean | True when a person put it there, which means a layout rebuild leaves it alone. False for a page the layout generated, which a rebuild replaces. |
heading
|
string, or null | The section name on a divider, the title on a note. |
body
|
string, or null | The words on a note. |
caption
|
string, or null | The line under a picture. |
inContents
|
boolean | Whether it appears in the table of contents. Dividers do; notes do not. |
recipe
|
object, or absent | The recipe on a recipe page: `id` and `name`. |
collection
|
object, or absent | The collection on a collection page: `id` and `name`. |
image
|
image, or absent | The photograph on a picture or divider page. |