Skip to content

Change a blog post

PATCH
/storefront/posts/{id}
curl --request PATCH \
--url https://example.com/storefront/posts/019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f \
--header 'Content-Type: application/json' \
--cookie __Host-bottle.session_token=<__Host-bottle.session_token> \
--data '{ "title": "example", "slug": "refills-and-swaps", "excerpt": "example", "bodyHtml": "example", "coverKey": "example", "coverAlt": "example", "authorName": "example", "publishedOn": "2026-04-15", "tags": [ "example" ], "seoTitle": "example", "seoDescription": "example", "status": "draft" }'

Only what is sent changes. status published puts it on the shop from publishedOn; draft takes it off. A new slug keeps the old address working: it sends shoppers on to the new one. The body is rich text: paragraphs, two sizes of heading, bold, italic, lists, quotes, links (https, email, or a path on the shop such as /delivery), pictures and product blocks. Anything else is removed, and it is cleaned again whenever it is read. A picture is <img src="/api/public/images/{key}/large" alt="…"> with a key from POST /storefront/assets and words saying what it shows; one without words, or from anywhere else, is dropped. A product block is <bottle-products data-ids="{id},{id}"></bottle-products> with up to four of the business’s own product ids; the shop draws each as a card with its live name, picture and price, and leaves out any not on sale.

id
required

UUID v7

string format: uuid

Example

019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f

UUID v7

Media typeapplication/json

Only what is sent changes. A new slug keeps the old address working: it sends shoppers on to the new one.

object
title
string
>= 1 characters <= 120 characters
slug

Lower-case letters, digits and single dashes, as in refills-and-swaps.

string
>= 1 characters <= 80 characters /^[a-z0-9]+(?:-[a-z0-9]+)*$/

Example

refills-and-swaps
excerpt
string
<= 300 characters
bodyHtml
string | null
<= 200000 characters
coverKey
string | null
<= 300 characters
coverAlt
string
<= 300 characters
authorName
string
<= 80 characters
publishedOn
string | null format: date
tags

Up to five short tags, such as Barbecues or Safety.

Array<string>
<= 5 items
seoTitle
string
<= 70 characters
seoDescription
string
<= 300 characters
status

Draft: only the business sees it, in the preview. published: on the shop.

string
Allowed values: draft published

The post

Media typeapplication/json
object
id
required

UUID v7

string format: uuid
slug
required
string
title
required
string
excerpt
required
string
bodyHtml
required
string | null
coverKey
required
string | null
coverAlt
required
string
cover
required
object
alt
required
string | null
width
required
integer
height
required
integer
thumb
required
string
card
required
string
large
required
string
authorName
required
string
publishedOn
required
string | null format: date
tags
required
Array<string>
seoTitle
required
string
seoDescription
required
string
status
required

Draft: only the business sees it, in the preview. published: on the shop.

string
Allowed values: draft published
createdAt
required
string format: date-time
updatedAt
required
string format: date-time
oldSlugs
required
Array<string>

Example

{
"id": "019205d1-6e7a-7c3b-9f6e-3a2b1c0d9e8f",
"status": "draft"
}

Not signed in

Media typeapplication/json
object
error
required
string
message
required
string

Example

{
"error": "not_found",
"message": "Customer not found"
}

The plan does not include a shop

Media typeapplication/json
object
error
required
string
message
required
string

Example

{
"error": "not_found",
"message": "Customer not found"
}

Not a member, or without the permission this needs

Media typeapplication/json
object
error
required
string
message
required
string

Example

{
"error": "not_found",
"message": "Customer not found"
}

No such post

Media typeapplication/json
object
error
required
string
message
required
string

Example

{
"error": "not_found",
"message": "Customer not found"
}

Another post has that address

Media typeapplication/json
object
error
required
string
message
required
string

Example

{
"error": "not_found",
"message": "Customer not found"
}

Validation failed

Media typeapplication/json
object
error
required
string
Allowed values: validation
message
required
string
issues
required
Array<object>
object
path
required
string
message
required
string

Example

{
"error": "validation",
"issues": [
{
"path": "email",
"message": "Invalid email"
}
]
}