# Content pages

> Render the pages the marketplace's team builds in the console (the home page, About, How it works) from blocks filled in with live data.

The marketplace's team builds pages in the console from blocks: a hero, listing grids, banners, category tiles and so on. Your storefront renders them, in its own design. You never hard-code the home page's content: the team changes it without a deploy.

## Fetch a page

```http
GET /v1/pages/home?locale=en&currency=EUR
```

`home` is the front page; other pages have their own address (`about`, `how-it-works`). Serve each at `/<slug>`. The answer has `title` and `description` (for `<title>` and the meta description), `share_image` (for `og:image`) and `blocks`, in order.

- `404` means the page isn't published. For `home`, fall back to a simple page of your own.
- Pages come in the marketplace's languages; without one in `locale`, you get the default language's page.
- `GET /v1/pages` lists every published page, for your sitemap.

## Render the blocks

Render each block by its `type`, and **skip types you don't know**, so new block types never break your shop. Blocks arrive filled in: listings with their photos and prices, images with their sizes, categories with their names, the showroom with its address. A block with nothing left to show (its listings all sold, a missing image) is left out, so you don't need to check.

| `type` | Show | Filled in |
|---|---|---|
| `hero` | `eyebrow`, `heading`, `text`, a search box when `search`, up to two `buttons`; beside it the `image` or the `listing` | `image`, `listing` |
| `links` | A row of `links` | |
| `listing_grid` | `heading`, a "view all" `link`, and the listing cards | `listings` |
| `banner` | A full-width `image` (`phone_image` on phones), with `heading` and `text` on it, linking to `link` | `image`, `phone_image` |
| `category_tiles` | `heading` and `tiles`: each tile's `image` and `label` (or its category's name), linking to the category | `tiles[].category`, `tiles[].image` |
| `image_text` | The `image` on `image_side`, beside `eyebrow`, `heading`, `text` and `link` | `image` |
| `featured_listing` | One `listing`, big, with `heading` and `text`. It may be sold (`stock` 0) when the team chose to keep it | `listing` |
| `cta` | A band in `tone` (brand, light or dark) with `heading`, `text` and up to two `buttons` | |
| `newsletter` | `heading`, `text`, an email field and `button_label` | |
| `promises` | `items`, each a `title` and `text` | |
| `showroom` | `heading`, `text`, and the `location`'s address and `opening_hours` | `location`, `image` |
| `text` | `body`, Markdown | |
| `faq` | `heading` and `questions`, each a `question` and a Markdown `answer` | |

Links (`href`) are a path in your shop (`/shop?sort=newest`) or an `https://` address. Listings in blocks are the same as in search, so reuse your listing card. Buttons have a `style`: `primary` or `secondary`.

Image URLs (`urls.thumb`, `medium`, `large`, `xlarge`) never change: cache them forever and use `srcset`.

## The newsletter block

Send the address from your server:

```http
POST /v1/newsletter/subscribers
{ "email": "mia@example.com", "first_name": "Mia", "locale": "en", "source": "home" }
```

It always answers `202` for a valid address (never revealing who's signed up), and a bad address gets `422`. mongrl keeps the list and adds the address to the marketplace's mailing tool.

## Preview

The console's **Preview** opens `https://<your shop>/<slug>?preview=<token>`. When that query is there, fetch the draft instead:

```http
GET /v1/pages/home/preview?token=<token>&currency=EUR
```

Don't cache previews, and add `<meta name="robots" content="noindex">` to them.
