# Cherished Book — API > Base URL `https://app.cherishedbook.com/api/v1` · MCP server `https://app.cherishedbook.com/api/mcp` > · OpenAPI https://www.cherishedbook.com/openapi/public.yaml Cherished Book holds online memorials for people and pets who have died. **Work out which of these you are before you start.** - **You can hold a token and make authenticated requests** (an MCP connector, or your own HTTP client). Then you can create a memorial and look after it directly. The rest of this document is for you. - **You can only read pages and write text back to a person.** Then you cannot create a memorial, and you must not imply that you have. What you can do is help them find the words, then hand them an onboarding link that opens the form already filled in. Skip to "Onboarding links" below. If you are unsure, assume the second. Telling a grieving person their memorial exists when it does not is the worst thing you can do here. There are two kinds of token. A **personal token** acts for one person, on memorials they look after. A **business token** is bound to one organisation (funeral homes, celebrants) and only ever sees that organisation's data. ## Connecting an AI assistant The quickest path is the MCP server at `https://app.cherishedbook.com/api/mcp`, which exposes these operations as tools. Authenticate it with a personal token. To get a token without asking anyone to copy and paste anything: ```http POST https://app.cherishedbook.com/api/v1/auth/device {"client_name": "Your App"} -> {device_code, user_code, verification_uri_complete, interval} # Show the person verification_uri_complete and ask them to approve it. POST https://app.cherishedbook.com/api/v1/auth/token {"device_code": "..."} -> 400 {"error": "authorization_pending"} keep polling at `interval` -> 200 {"access_token": "..."} store this ``` Then send `Authorization: Bearer ` on every request. Approving requires signing in, which is also how the person's email address is confirmed. Nothing needs verifying a second time afterwards. ## Onboarding links For when you cannot make authenticated requests. Build a URL, give it to the person, and they land on the create-a-memorial form with the boxes filled in. No token, no setup, nothing to install. ``` https://app.cherishedbook.com/start?name=Margaret%20Hill&born=1948-03-02&died=2026-07-14&ref=your-name ``` | Parameter | Values | |---|---| | `name` | required, up to 255 | | `type` | `person` (default) or `pet` | | `mode` | `self` (your wording) or `ai` (our writing help works from your notes) | | `born`, `died` | `YYYY-MM-DD`; ignored if unreadable or in the future | | `species` | pets only, e.g. `dog` | | `notes` | up to 1000, for `mode=ai`. Facts, not prose | | `title`, `subtitle` | up to 255, for `mode=self` | | `story` | up to 1500, the obituary, for `mode=self` | | `feel`, `tradition` | optional tone hints | | `ref` | `a-z0-9-`, up to 32. Identify yourself here | Keep the whole URL under about 2,000 characters. Over-long values are dropped, not truncated. A parameter you get wrong is ignored rather than shown as an error, so a mistake never dead-ends the person. **What a link does not do.** It does not create anything. A memorial exists only once the person completes the form and confirms their email address. So do not tell them it is done, do not promise a web address, and do not say it is published. Say you have prepared it and they need to finish it. Full contract: https://www.cherishedbook.com/developers/links ## Before you call anything - **Nothing is published until it has been safety-checked.** Creating or rewording a memorial returns `202` with a moderation status of `pending`. Poll until it changes. Never tell someone their memorial is live before a response says so. - **Send a whole edit in one request.** Changes to wording are checked one at a time, five minutes apart per memorial. Settings like privacy and template are unlimited. - **You act for one person**, on memorials they look after. You cannot see anyone else's, and you cannot email anyone through this API. - **Ask gently.** The people using this are usually recently bereaved. Only a name is required to create a memorial. Do not press for dates they may not want to give. - **Confirm before destructive things** — deleting a memorial, or hiding a tribute somebody wrote. ## Creating and looking after memorials These need a personal token. ### `POST /me/memorials` — create a memorial Only `deceased_name` is required. Optional: `title`, `subtitle`, `obituary`, `birth_date`, `death_date`. Supply `obituary` and those words are kept exactly as written. Leave it out and one is drafted for the family to edit. Returns `202` with a `poll_url`. Poll it until `ready` or `blocked`. A `409` means a limit was reached: five memorials at a time, three a day. ### `GET /me/drafts/{id}` — check one being created `generating` means keep waiting. `ready` means it is live. `blocked` means the safety check refused it, and `reason` says why so you can suggest a rewording. ### `GET /me/memorials` — list the ones this person looks after ### `GET /me/memorials/{id}` — get one ### `PATCH /me/memorials/{id}` — edit Send every change in ONE request. Wording fields (`deceased_name`, `title`, `subtitle`, `description`, `resting_place_notes`) are safety-checked and limited to one change per memorial per five minutes; a `429` carries `Retry-After`. Settings (`privacy`, `is_published`, `contributions_enabled`, `manual_content_approval`, `hide_from_search`, `template_id`, `birth_date`, `death_date`, `resting_place_url`) are unlimited. ### `GET /me/memorials/{id}/status` — has the safety check finished ### `DELETE /me/memorials/{id}` — delete Recoverable from the owner's dashboard, never destroyed immediately. Confirm first. ### `POST /me/memorials/{id}/media` — get a link for uploading a photo Returns a short-lived signed URL. `PUT` the JPEG to it as multipart form-data in the `file` field. Never send an image as base64 in the conversation. ## Tributes people leave ### `GET /memorials/{id}/contributions` — read them Use `status` to choose between `pending`, `approved`, `rejected` and `deleted`. Check `can_approve` before offering to publish: a tribute the safety check refused, or one whose writer has not confirmed their email, cannot be published. ### `POST /contributions/{id}/approve` — publish one ### `POST /contributions/{id}/reject` — reject one, optionally with a `reason` ### `DELETE /contributions/{id}` — hide one ### `POST /contributions/{id}/restore` — put a hidden one back ## For organisations These need a business token, minted by a Business Admin in Business settings. ### `GET /organization` — profile, branding and memorial counts ### `GET /owners` — owner name and email for the organisation's memorials ### `GET /memorials` — the organisation's memorials, live and pending ### `POST /memorials` — provision a memorial for a family `action: invite` (default) emails the family a link to complete it. `action: complete` means the organisation supplies the content and it goes live. ### `POST /memorials/{id}/invitation` — re-send the family invitation ## Everything else ### `GET /ping` — check a token and see what it may do Rate limits: 20 requests a minute for a personal token, 50 for a business token. Errors use conventional status codes with a `message` written to be read aloud: `401` no or bad token, `403` wrong kind of token for that endpoint, `404` not yours, `409` a limit was reached, `422` validation, `429` slow down. - Full specification: https://www.cherishedbook.com/openapi/public.yaml - Human reference: https://www.cherishedbook.com/developers - Plain-English overview: https://www.cherishedbook.com/mcp