Criar e gerenciar layouts
Cria, renomeia, duplica, promove a padrão e exclui layouts avançados da loja.
Um layout é a "planta" completa da vitrine. A loja pode ter vários, mas só o marcado como padrão (is_default) é servido aos clientes. Estas cinco rotas cobrem o ciclo de vida do layout inteiro. Para editar o conteúdo dele, veja as páginas de estrutura e de blocos.
Criar layout
Cria um layout novo. Por padrão ele nasce como cópia profunda do layout padrão atual (mesmas páginas, linhas e blocos), para você partir de uma base que funciona. Se a loja ainda não tem layout padrão, ou se você enviar seed_blank: true, nasce um layout vazio.
/api/v1/admin/advanced-layoutsAdminCriar um layout
Requer o privilégio manage_layouts.
Corpo da requisição
namestringobrigatóriotheme_variantstringpadrão: defaultis_defaultbooleanpadrão: falseseed_blankbooleanpadrão: falsetrue cria um layout vazio em vez de copiar o padrão.theme_iduuidExemplo de requisição
curl -X POST "$BASE_URL/api/v1/admin/advanced-layouts" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Layout da Black Friday",
"seed_blank": false
}'Resposta
{
"id": 135,
"name": "Novo Layout Avançado",
"theme_variant": "default",
"is_default": false,
"pages": [
{
"id": 2930,
"layout_id": 135,
"dispatch": "index.index",
"name": "Homepage",
"is_default": false,
"position": 1,
"seo_title": "",
"seo_description": "",
"seo_keywords": "",
"og_image": "",
"og_type": "website",
"canonical_url": "",
"no_index": false,
"custom_html_code": "",
"created_at": "2026-07-12T16:29:12.505299Z",
"containers": [
{
"id": 11056,
"page_id": 2930,
"position": "content",
"sort_order": 0,
"uses_default": false,
"rows": [
{
"id": 8029,
"container_id": 11056,
"sort_order": 0,
"full_width": false,
"spacing": "normal",
"display_mode": "normal",
"visibility": {
"desktop": true,
"tablet": true,
"mobile": true
},
"columns": [
{
"id": 8786,
"row_id": 8029,
"sort_order": 0,
"width_desktop": 12,
"width_tablet": 12,
"width_mobile": 12,
"visibility": {
"desktop": true,
"tablet": true,
"mobile": true
},
"blocks": [
{
"id": 11081,
"column_id": 8786,
"block_type": "banner_slider",
"sort_order": 0,
"name": "Main Banner",
"config": {
"autoplay": true,
"interval": 5000,
"show_arrows": true
},
"content": {},
"visibility": {
"desktop": true,
"tablet": true,
"mobile": true
},
"status": "A",
"cache_ttl": 300,
"updated_at": "2026-07-12T16:29:12.505299Z"
}
]
}
]
}
]
}
]
}
],
"created_at": "2026-07-12T16:29:12.505299Z",
"updated_at": "2026-07-12T16:29:12.505299Z"
}Campos da resposta
idintegernamestringtheme_variantstringdefault, machic...). É só um rótulo para o editor.is_defaultbooleantrue no layout que a vitrine está servindo. Só um por loja (e por tema).pagesarrayGET por id cada página traz containers, com linhas, colunas e blocos aninhados.created_atstringupdated_atstringErros
| Status | Quando | Corpo de exemplo |
|---|---|---|
| 400 | Corpo JSON inválido. | {"error":"invalid request body","detail":"unexpected EOF"} |
| 400 | name vazio. | {"error":"name is required"} |
| 401 | Sem token, token inválido ou expirado. | {"error":"invalid or expired token"} |
| 403 | Seu usuário não tem o privilégio manage_layouts. | {"error":"insufficient privileges","required":"manage_layouts"} |
| 500 | Falha ao gravar ou ler no banco, ou id inexistente onde a rota não trata 404. | {"error":"failed to create layout","detail":"..."} |
Atualizar layout
Altera o nome, a variante ou o flag de padrão. Todos os campos são opcionais e só os enviados mudam. Enviar is_default: true rebaixa o layout padrão anterior na mesma transação, então a loja nunca fica com dois padrões.
/api/v1/admin/advanced-layouts/{id}AdminAtualizar nome, variante ou padrão
Requer o privilégio manage_layouts.
Parâmetros de caminho
idintegerobrigatórioCorpo da requisição
namestringtheme_variantstringis_defaultbooleantrue promove a padrão.Exemplo de requisição
curl -X PUT "$BASE_URL/api/v1/admin/advanced-layouts/135" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Layout da Black Friday 2026"
}'Resposta
{
"id": 135,
"name": "Novo Layout Avançado",
"theme_variant": "default",
"is_default": false,
"created_at": "2026-07-12T16:29:12.505299Z",
"updated_at": "2026-07-12T16:29:12.505299Z"
}Campos da resposta
idintegernamestringtheme_variantstringdefault, machic...). É só um rótulo para o editor.is_defaultbooleantrue no layout que a vitrine está servindo. Só um por loja (e por tema).created_atstringupdated_atstringErros
| Status | Quando | Corpo de exemplo |
|---|---|---|
| 400 | O id de layout no caminho não é um inteiro. | {"error":"invalid layout id","detail":"id must be an integer"} |
| 400 | Corpo JSON inválido. | {"error":"invalid request body","detail":"unexpected EOF"} |
| 401 | Sem token, token inválido ou expirado. | {"error":"invalid or expired token"} |
| 403 | Seu usuário não tem o privilégio manage_layouts. | {"error":"insufficient privileges","required":"manage_layouts"} |
| 500 | Falha ao gravar ou ler no banco, ou id inexistente onde a rota não trata 404. | {"error":"failed to update layout","detail":"..."} |
Excluir layout
Exclui o layout e toda a sua árvore (páginas, contêineres, linhas, colunas, blocos). Não dá para excluir o layout padrão: promova outro antes.
/api/v1/admin/advanced-layouts/{id}AdminExcluir um layout
Requer o privilégio manage_layouts.
Parâmetros de caminho
idintegerobrigatórioExemplo de requisição
curl -X DELETE "$BASE_URL/api/v1/admin/advanced-layouts/135" \
-H "Authorization: Bearer $TOKEN"Resposta
{
"message": "layout deleted"
}Erros
| Status | Quando | Corpo de exemplo |
|---|---|---|
| 400 | O id de layout no caminho não é um inteiro. | {"error":"invalid layout id","detail":"id must be an integer"} |
| 401 | Sem token, token inválido ou expirado. | {"error":"invalid or expired token"} |
| 403 | Seu usuário não tem o privilégio manage_layouts. | {"error":"insufficient privileges","required":"manage_layouts"} |
| 404 | Layout não existe. | {"error":"layout not found","detail":"135"} |
| 409 | É o layout padrão. | {"error":"cannot delete default layout","detail":"promote another layout to default before deleting this one"} |
| 500 | Falha ao gravar ou ler no banco, ou id inexistente onde a rota não trata 404. | {"error":"failed to delete layout","detail":"..."} |
Duplicar layout
Copia o layout inteiro (páginas, contêineres, linhas, colunas e blocos) para um layout novo, não padrão, e devolve a árvore da cópia. Se name vier vazio, o nome é <original> (copy). O corpo é opcional.
/api/v1/admin/advanced-layouts/{id}/cloneAdminDuplicar um layout
Requer o privilégio manage_layouts.
Parâmetros de caminho
idintegerobrigatórioCorpo da requisição
namestringExemplo de requisição
curl -X POST "$BASE_URL/api/v1/admin/advanced-layouts/135/clone" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Teste de rodapé"
}'Resposta
{
"id": 136,
"name": "Teste de rodapé",
"theme_variant": "default",
"is_default": false,
"pages": [
{
"id": 2930,
"layout_id": 135,
"dispatch": "index.index",
"name": "Homepage",
"is_default": false,
"position": 1,
"seo_title": "",
"seo_description": "",
"seo_keywords": "",
"og_image": "",
"og_type": "website",
"canonical_url": "",
"no_index": false,
"custom_html_code": "",
"created_at": "2026-07-12T16:29:12.505299Z",
"containers": [
{
"id": 11056,
"page_id": 2930,
"position": "content",
"sort_order": 0,
"uses_default": false,
"rows": [
{
"id": 8029,
"container_id": 11056,
"sort_order": 0,
"full_width": false,
"spacing": "normal",
"display_mode": "normal",
"visibility": {
"desktop": true,
"tablet": true,
"mobile": true
},
"columns": [
{
"id": 8786,
"row_id": 8029,
"sort_order": 0,
"width_desktop": 12,
"width_tablet": 12,
"width_mobile": 12,
"visibility": {
"desktop": true,
"tablet": true,
"mobile": true
},
"blocks": [
{
"id": 11081,
"column_id": 8786,
"block_type": "banner_slider",
"sort_order": 0,
"name": "Main Banner",
"config": {
"autoplay": true,
"interval": 5000,
"show_arrows": true
},
"content": {},
"visibility": {
"desktop": true,
"tablet": true,
"mobile": true
},
"status": "A",
"cache_ttl": 300,
"updated_at": "2026-07-12T16:29:12.505299Z"
}
]
}
]
}
]
}
]
}
],
"created_at": "2026-07-12T16:29:12.505299Z",
"updated_at": "2026-07-12T16:29:12.505299Z"
}Campos da resposta
idintegernamestringtheme_variantstringdefault, machic...). É só um rótulo para o editor.is_defaultbooleantrue no layout que a vitrine está servindo. Só um por loja (e por tema).pagesarrayGET por id cada página traz containers, com linhas, colunas e blocos aninhados.created_atstringupdated_atstringErros
| Status | Quando | Corpo de exemplo |
|---|---|---|
| 400 | O id de layout no caminho não é um inteiro. | {"error":"invalid layout id","detail":"id must be an integer"} |
| 401 | Sem token, token inválido ou expirado. | {"error":"invalid or expired token"} |
| 403 | Seu usuário não tem o privilégio manage_layouts. | {"error":"insufficient privileges","required":"manage_layouts"} |
| 404 | O layout de origem não existe. | {"error":"layout not found","detail":"135"} |
| 500 | Falha ao gravar ou ler no banco, ou id inexistente onde a rota não trata 404. | {"error":"failed to clone layout","detail":"..."} |
Definir layout padrão
Torna o layout o único padrão da loja: o flag é removido de todos os outros na mesma transação. A vitrine passa a servir esse layout na próxima requisição de página. Não há corpo.
/api/v1/admin/advanced-layouts/{id}/set-defaultAdminPromover um layout a padrão
Requer o privilégio manage_layouts.
Parâmetros de caminho
idintegerobrigatórioExemplo de requisição
curl -X POST "$BASE_URL/api/v1/admin/advanced-layouts/135/set-default" \
-H "Authorization: Bearer $TOKEN"Resposta
{
"id": 135,
"name": "Novo Layout Avançado",
"theme_variant": "default",
"is_default": true,
"created_at": "2026-07-12T16:29:12.505299Z",
"updated_at": "2026-07-12T16:29:12.505299Z"
}Campos da resposta
idintegernamestringtheme_variantstringdefault, machic...). É só um rótulo para o editor.is_defaultbooleantrue no layout que a vitrine está servindo. Só um por loja (e por tema).created_atstringupdated_atstringErros
| Status | Quando | Corpo de exemplo |
|---|---|---|
| 400 | O id de layout no caminho não é um inteiro. | {"error":"invalid layout id","detail":"id must be an integer"} |
| 401 | Sem token, token inválido ou expirado. | {"error":"invalid or expired token"} |
| 403 | Seu usuário não tem o privilégio manage_layouts. | {"error":"insufficient privileges","required":"manage_layouts"} |
| 404 | Layout não existe. | {"error":"layout not found","detail":"135"} |
| 500 | Falha ao gravar ou ler no banco, ou id inexistente onde a rota não trata 404. | {"error":"failed to set default layout","detail":"..."} |