Appearance
Posts
O módulo de posts é o coração do seu blog. Ele permite que você crie, gerencie e publique artigos ricos em conteúdo, com suporte a SEO, categorias, tags e imagens de capa.
Cada post possui um ciclo de vida simples: ele nasce como rascunho (draft) e, quando estiver pronto, pode ser publicado (published) — com uma data de publicação opcional para agendamento.
Estrutura de Dados Principal
Um post contém as seguintes informações principais:
| Campo | Tipo | Descrição |
|---|---|---|
title | String | Título principal do artigo (máx. 150 caracteres). |
slug | String | URL amigável única no blog (ex: meu-artigo-incrivel). |
excerpt | String | Resumo curto do artigo (máx. 500 caracteres). |
content | String | Conteúdo completo (suporta HTML). |
readingTime | Integer | Tempo de leitura estimado em segundos (calculado automaticamente a partir do conteúdo). |
status | Enum | draft ou published. |
isFeatured | Boolean | Indica se o post está em destaque. |
viewCount | Integer | Contador de visualizações (incrementado a cada acesso público por slug). |
publishedAt | Date | Data de publicação (formato YYYY-MM-DD HH:mm:ss). |
seoTitle | String | Título para SEO (máx. 200 caracteres). |
seoDescription | String | Descrição para SEO (máx. 200 caracteres). |
seoKeywords | String | Palavras-chave para SEO (máx. 200 caracteres). |
Endpoints Públicos
Estes endpoints são voltados para o frontend do blog e não exigem autenticação administrativa — apenas o header X-Blog-Id. Eles retornam apenas posts com o status published.
Listar Posts Publicados
Retorna uma lista paginada de todos os posts publicados.
http
GET /v1/blog/posts/public/publishedParâmetros de Query
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
page | number | Não | O número da página (mínimo: 1). |
perPage | number | Não | Itens por página. |
search | string | Não | Busca por termo no título (máx. 150 caracteres). |
isFeatured | boolean | Não | Filtra apenas posts em destaque. |
categories | number[] | Não | Filtra por IDs de categorias (ex: categories[]=5). |
tags | number[] | Não | Filtra por IDs de tags (ex: tags[]=1&tags[]=2). |
orderBy | enum | Não | Campo de ordenação: id, title ou createdAt. |
orderDirection | enum | Não | Direção da ordenação: asc ou desc. |
Exemplo de Requisição
bash
curl -X GET "https://api.us.basis.tavares.in/v1/blog/posts/public/published?page=1&perPage=10" \
-H "X-Blog-Id: {blog-id}" \
-H "Accept: application/json"Respostas
200 OK
Retorna um objeto de paginação contendo a lista de posts publicados.
json
{
"meta": {
"currentPage": "1",
"perPage": "25"
},
"data": [
{
"id": "16",
"blogUserId": "6",
"blogImageId": "7",
"title": "Novidades da Versão 2.0",
"slug": "novidades-versao-2-0",
"excerpt": "Um resumo sobre as novidades...",
"seoTitle": "Novidades da Versão 2.0",
"seoDescription": "Conheça tudo o que chegou na versão 2.0.",
"seoKeywords": "novidades, versão, release",
"createdAt": "2026-03-25T16:24:24.411-03:00",
"updatedAt": "2026-03-25T16:53:33.693-03:00",
"readingTime": 29,
"isFeatured": true,
"viewCount": "11111",
"publishedAt": "2026-03-25T17:17:00.000+00:00",
"status": "published",
"blogImage": {
"id": "7",
"name": "capa.jpg",
"uri": "https://cdn.exemplo.com/images/4efdbdfa-b867-4821-aa63-8e135eac8bb2.jpg"
},
"blogUser": {
"id": "6",
"firstName": "Maria",
"lastName": "Silva",
"email": "autor@exemplo.com",
"blogImageId": "5",
"blogImage": {
"id": "5",
"name": "avatar.jpg",
"uri": "https://cdn.exemplo.com/images/1635fe4c-c41f-439b-8dd8-0ab0613d569e.jpg"
}
}
}
]
}Obter Post por Slug
Recupera os detalhes completos de um post publicado através do seu slug único. Cada acesso a este endpoint incrementa o viewCount do post.
http
GET /v1/blog/posts/public/slug/:slugParâmetros de Rota
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
slug | string | Sim | O slug único do post (ex: novidades-versao-2-0). |
Exemplo de Requisição
javascript
fetch('https://api.us.basis.tavares.in/v1/blog/posts/public/slug/novidades-versao-2-0', {
headers: { 'X-Blog-Id': '{blog-id}' }
})
.then(response => response.json())
.then(data => console.log(data));Respostas
200 OK
Retorna o post completo, incluindo content, autor e imagem de capa.
json
{
"id": "16",
"title": "Novidades da Versão 2.0",
"slug": "novidades-versao-2-0",
"excerpt": "Um resumo sobre as novidades...",
"content": "<p>Conteúdo completo do artigo...</p>",
"seoTitle": "Novidades da Versão 2.0",
"seoDescription": "Conheça tudo o que chegou na versão 2.0.",
"seoKeywords": "novidades, versão, release",
"createdAt": "2026-03-25T16:24:24.411-03:00",
"updatedAt": "2026-03-25T16:51:11.991-03:00",
"blogUserId": "6",
"blogImageId": "7",
"readingTime": 29,
"isFeatured": true,
"viewCount": "1111",
"status": "published",
"blogImage": {
"id": "7",
"name": "capa.jpg",
"uri": "https://cdn.exemplo.com/images/4efdbdfa-b867-4821-aa63-8e135eac8bb2.jpg"
},
"blogUser": {
"id": "6",
"firstName": "Maria",
"lastName": "Silva",
"email": "autor@exemplo.com",
"blogImageId": "5",
"bio": null,
"blogImage": {
"id": "5",
"name": "avatar.jpg",
"uri": "https://cdn.exemplo.com/images/1635fe4c-c41f-439b-8dd8-0ab0613d569e.jpg"
}
}
}404 Not Found
Ocorre quando o post não existe ou não está publicado.
Obter Post por ID
Recupera os detalhes completos de um post publicado através do seu ID.
http
GET /v1/blog/posts/public/:idParâmetros de Rota
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | number | Sim | O ID do post publicado. |
Respostas
200 OK
Retorna o post completo, na mesma estrutura do endpoint por slug.
Endpoints Administrativos
Endpoints protegidos para gerenciamento de conteúdo. Requerem autenticação de usuário do blog (Authorization: Bearer {token} e X-Blog-Id).
Listar Todos os Posts
Lista todos os posts do blog, incluindo rascunhos.
http
GET /v1/blog/postsParâmetros de Query
Além dos filtros de paginação e busca (page, perPage, search, orderBy, orderDirection), permite filtrar por status, destaque, categorias e tags:
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
status | enum | Não | Filtra por published ou draft. |
isFeatured | boolean | Não | Filtra apenas posts em destaque. |
categories | number[] | Não | Filtra por IDs de categorias. |
tags | number[] | Não | Filtra por IDs de tags. |
Exemplo de Requisição
bash
curl -X GET "https://api.us.basis.tavares.in/v1/blog/posts?page=1&perPage=15&status=draft&tags[]=2" \
-H "Authorization: Bearer {token}" \
-H "X-Blog-Id: {blog-id}"Respostas
200 OK
Retorna a lista paginada de posts, incluindo tags e categorias vinculadas.
json
{
"meta": {
"currentPage": "1",
"perPage": "25"
},
"data": [
{
"id": "17",
"blogUserId": "6",
"blogImageId": "5",
"title": "Novidades da Versão 2.0",
"slug": "novidades-versao-2-0",
"excerpt": "Um resumo sobre as novidades...",
"seoTitle": "Novidades da Versão 2.0",
"seoDescription": "Conheça tudo o que chegou na versão 2.0.",
"seoKeywords": "novidades, versão, release",
"createdAt": "2026-03-30T00:45:48.940+00:00",
"updatedAt": "2026-03-30T00:45:48.940+00:00",
"readingTime": 29,
"isFeatured": true,
"viewCount": "0",
"publishedAt": null,
"status": "draft",
"blogTags": [
{ "id": "1", "name": "Release" },
{ "id": "2", "name": "Produto" }
],
"blogImage": {
"id": "5",
"name": "capa.jpg",
"uri": "https://cdn.exemplo.com/images/1635fe4c-c41f-439b-8dd8-0ab0613d569e.jpg"
},
"blogCategories": [
{ "id": "5", "name": "Tecnologia" },
{ "id": "6", "name": "Desenvolvimento" }
],
"blogUser": {
"id": "6",
"firstName": "Maria",
"lastName": "Silva",
"email": "autor@exemplo.com",
"blogImageId": "5",
"blogImage": {
"id": "5",
"name": "avatar.jpg",
"uri": "https://cdn.exemplo.com/images/1635fe4c-c41f-439b-8dd8-0ab0613d569e.jpg"
}
}
}
]
}Criar Novo Post
Cria um novo post e vincula categorias e tags. O autor (blogUserId) é definido automaticamente como o usuário autenticado, e o readingTime é calculado a partir do conteúdo.
http
POST /v1/blog/postsPayload (Body)
| Atributo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
post.title | string | Sim | Título (máx. 150 caracteres). |
post.slug | string | Sim | Slug único no blog (máx. 150 caracteres). |
post.content | string | Sim | Conteúdo principal em HTML (máx. 1.000.000 caracteres). |
post.blogImageId | number | Sim | ID da imagem de capa (deve pertencer ao blog). |
post.status | enum | Sim | draft ou published. |
post.isFeatured | boolean | Sim | Define se o post fica em destaque. |
post.excerpt | string | Não | Resumo do artigo (máx. 500 caracteres). Aceita null. |
post.seoTitle | string | Não | Título SEO (máx. 200 caracteres). Aceita null. |
post.seoDescription | string | Não | Descrição SEO (máx. 200 caracteres). Aceita null. |
post.seoKeywords | string | Não | Palavras-chave SEO (máx. 200 caracteres). Aceita null. |
post.publishedAt | date | Não | Data de publicação no formato YYYY-MM-DD HH:mm:ss. Aceita null. |
tags | number[] | Não | IDs das tags (ex: [1, 2]). Aceita null. |
categories | number[] | Não | IDs das categorias (ex: [5]). Aceita null. |
Exemplo de Requisição
bash
curl -X POST "https://api.us.basis.tavares.in/v1/blog/posts" \
-H "Authorization: Bearer {token}" \
-H "X-Blog-Id: {blog-id}" \
-H "Content-Type: application/json" \
-d '{
"post": {
"blogImageId": 5,
"title": "Novo Artigo",
"slug": "novo-artigo",
"excerpt": "Um breve resumo do artigo.",
"content": "<p>Conteúdo aqui...</p>",
"seoTitle": "Novo Artigo",
"seoDescription": "Descrição do novo artigo.",
"seoKeywords": "artigo, blog",
"isFeatured": true,
"status": "published",
"publishedAt": null
},
"tags": [1, 2],
"categories": [5]
}'Respostas
201 Created
Retorna o ID do post criado.
json
{
"id": "18"
}422 Unprocessable Entity
Erro de validação nos campos enviados.
json
{
"errors": [
{
"message": "Slug já cadastrado",
"rule": "database.unique",
"field": "post.slug"
}
]
}Obter Post por ID (Gerenciamento)
Recupera todos os dados de um post, independente do status, para edição no dashboard.
http
GET /v1/blog/posts/:idParâmetros de Rota
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | number | Sim | O ID do post. |
Respostas
200 OK
Retorna o post completo, incluindo content, blogTags e blogCategories.
404 Not Found
Ocorre quando o post não existe no blog.
Atualizar Post
Atualiza um post existente. Os campos title, slug, status, content e isFeatured são obrigatórios (envie o objeto completo). O tempo de leitura é recalculado automaticamente e os vínculos de tags e categorias são substituídos pelos arrays enviados.
http
PUT /v1/blog/posts/:idExemplo de Requisição
bash
curl -X PUT "https://api.us.basis.tavares.in/v1/blog/posts/18" \
-H "Authorization: Bearer {token}" \
-H "X-Blog-Id: {blog-id}" \
-H "Content-Type: application/json" \
-d '{
"post": {
"blogImageId": 7,
"title": "Título Atualizado",
"slug": "titulo-atualizado",
"excerpt": "Resumo atualizado.",
"content": "<p>Conteúdo atualizado...</p>",
"seoTitle": "Título Atualizado",
"seoDescription": "Descrição atualizada.",
"seoKeywords": "artigo, atualizado",
"isFeatured": true,
"status": "published",
"publishedAt": "2026-03-25 17:17:00"
},
"tags": [1, 2],
"categories": [5, 6]
}'Respostas
204 No Content
Post atualizado com sucesso. A resposta não contém corpo.
Alterar Status do Post
Atalho para publicar ou despublicar um post sem reenviar todos os dados.
http
PATCH /v1/blog/posts/change-status/:idParâmetros do Body
| Atributo | Tipo | Obrigatório | Descrição |
|---|---|---|---|
status | enum | Sim | Novo status: draft ou published. |
Exemplo de Requisição
bash
curl -X PATCH "https://api.us.basis.tavares.in/v1/blog/posts/change-status/18" \
-H "Authorization: Bearer {token}" \
-H "X-Blog-Id: {blog-id}" \
-H "Content-Type: application/json" \
-d '{
"status": "published"
}'Respostas
204 No Content
Status alterado com sucesso. A resposta não contém corpo.
Remover Post
Exclui um post permanentemente (Soft Delete).
http
DELETE /v1/blog/posts/:idExemplo de Requisição
bash
curl -X DELETE "https://api.us.basis.tavares.in/v1/blog/posts/18" \
-H "Authorization: Bearer {token}" \
-H "X-Blog-Id: {blog-id}"Respostas
204 No Content
Remoção concluída com sucesso. A resposta não contém corpo.