Search Documentation

Search for a documentation page...

Posts API

REST API endpoints for managing blog posts.

List Posts

GET /api/v1/posts

Query Parameters

ParameterTypeDefaultDescription
limitnumber50Posts per page (1-100)
offsetnumber0Posts to skip
querystringSearch by post title
activebooleanFilter by published status
tagstringFilter by tag
categoryIdstringFilter by blog category ID
langstringLocale code (e.g. pl-PL) to overlay translated fields onto the response. Only honoured when the store's translations tool is enabled.

Response

{
"data": [
{
"id": "0191abc0-1234-7def-8000-000000000001",
"title": "Welcome to Our Store",
"slug": "welcome-to-our-store",
"image": "https://cdn.example.com/welcome.jpg",
"tag": "news",
"active": true,
"publishedAt": "2024-06-01T12:00:00.000Z",
"createdAt": "2024-05-28T09:00:00.000Z"
}
],
"meta": {
"count": 12
},
"lang": "pl-PL"
}

Get Post

GET /api/v1/posts/:idOrSlug

Returns a single blog post by UUID or slug, with full TipTap JSON content and SEO metadata.

ParameterTypeDescription
langstringLocale code for translated field overlay and translated slug lookup

When ?lang= is provided and translations are enabled, the endpoint overlays translated title, slug, content, seo.title, and seo.description onto the response. The post can also be looked up by its translated slug – if no base slug matches, the endpoint tries the translated slug for the given locale.


Create Post

POST /api/v1/posts

Content must be valid TipTap JSON with type: "doc". The slug must be unique within the store.

External image URLs – both the featured image field and any image or imageResize nodes inside content – are automatically downloaded and re-hosted on the store's own CDN. The response will contain the re-hosted URLs, not the original URLs you submitted. Images that already belong to the store are left untouched. If an image cannot be fetched, the original URL is preserved.

Request Body

FieldTypeRequiredDescription
titlestringYesPost title
slugstringYesURL slug (lowercase, numbers, hyphens)
contentobjectYesTipTap JSON content ({ type: "doc", content: [...] })
imagestringNoFeatured image URL
tagstringNoPost tag/category
activebooleanNoVisible on storefront
publishedAtstringNoISO 8601 publication date
seoobjectNoSEO metadata (see below)
filtersobjectNoKey-value metadata filters

SEO Object

FieldTypeDescription
titlestringMeta title
descriptionstringMeta description
canonicalstringCanonical URL
curl -X POST \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"title": "Welcome to Our Store",
"slug": "welcome-to-our-store",
"content": {
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{ "type": "text", "text": "Hello and welcome!" }
]
}
]
},
"tag": "news",
"active": true,
"seo": {
"title": "Welcome | Our Store",
"description": "Learn about our store and products."
}
}' \
https://your-store.yns.store/api/v1/posts

Update Post

PATCH /api/v1/posts/:idOrSlug

Partially updates a blog post. Only the provided fields are changed. Accepts the same fields as create (all optional). Image re-hosting applies to updates as well – any new external image URLs are re-hosted, while omitted fields are left unchanged.


Delete Post

DELETE /api/v1/posts/:idOrSlug

Permanently deletes a blog post.


Translations

PUT /api/v1/posts/:idOrSlug/translations/:locale

Upsert or delete a single locale's translated fields for a blog post. The post can be identified by UUID or base slug. The locale must be a supported locale code (e.g. pl-PL) and cannot be the store's base locale – base content is edited via PATCH /api/v1/posts/:idOrSlug.

Request Body

FieldTypeDescription
titlestringTranslated post title
slugstringTranslated URL slug
contentobjectTranslated body (TipTap JSONContent)
seoTitlestringTranslated SEO title
seoDescriptionstringTranslated SEO description

All fields are optional. The schema is strict – unknown fields are rejected. Sending an empty body (all fields omitted or blank) deletes the translation row, so the post falls back to its base-language content.

The locale does not need to be enabled in settings.enabledLanguages – you can stage translations before flipping the language on.

curl -X PUT \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{
"title": "Witamy w naszym sklepie",
"slug": "witamy-w-naszym-sklepie",
"seoTitle": "Witamy | Nasz sklep"
}' \
https://your-store.yns.store/api/v1/posts/welcome-to-our-store/translations/pl-PL

Response

{
"ok": true,
"postId": "0191abc0-1234-7def-8000-000000000001",
"locale": "pl-PL",
"deleted": false
}

Errors

StatusMeaning
400Unsupported locale, or the locale is the store's base locale
404No post matches the identifier
409A translation with this slug already exists for the same locale

See the Localization page for the full translation behaviour and conventions.


Post Comments

List Comments

GET /api/v1/posts/:idOrSlug/comments

Returns approved comments for a post. Pending comments are only visible in the admin interface.

ParameterTypeDefaultDescription
limitnumber20Comments per page (1-100)
offsetnumber0Comments to skip
{
"data": [
{
"id": "0191abc0-1234-7def-8000-000000000001",
"author": "Jane Doe",
"content": "Great article, very helpful!",
"createdAt": "2024-06-15T14:30:00.000Z"
}
],
"meta": {
"count": 1,
"offset": 0,
"limit": 20
}
}

Create Comment

POST /api/v1/posts/:idOrSlug/comments

Submits a comment (pending approval by store owner). The email field is stored but not returned in responses.

FieldTypeRequiredDescription
authorstringYesDisplay name (1-100 chars)
emailstringYesEmail address
contentstringYesComment text (1-5000 chars)
curl -X POST \
-H "Authorization: Bearer your_api_key" \
-H "Content-Type: application/json" \
-d '{"author": "Jane", "email": "jane@example.com", "content": "Great article!"}' \
https://your-store.yns.store/api/v1/posts/my-post/comments

Response (201)

{
"id": "0191abc0-1234-7def-8000-000000000001",
"author": "Jane",
"content": "Great article!",
"createdAt": "2024-06-15T14:30:00.000Z"
}