API reference

Books

Books built from collections, and the epub they compile to.

Paths below are relative to https://recipejam.com/api/v1

GET /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.

POST /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.
GET /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.

PATCH /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.
DELETE /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.
POST /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.
POST /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.
GET /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.

POST /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.
PATCH /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.

DELETE /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.
GET /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.