HystoreWiki

3 min de leituraVer em Markdown

API do tema

https://theme.hystore.com.br/v1 lê e muda o tema em código de uma loja. É a API que a ferramenta hystore usa, aberta para as suas integrações e para CI. A lista completa de rotas, com os formatos, está na OpenAPI.

1. Crie uma chave

  1. No painel, abra Personalização > Acesso ao tema > Criar chave.
  2. Dê um nome (por exemplo, Deploy do site).
  3. Escolha o que ela pode fazer:
Escopo Permite
theme:read ler arquivos, versões e mídia; conferir; links de prévia
theme:write mudar o rascunho, imagens e fontes; trazer uma versão de volta
theme:publish-request pedir publicação (aprovada no painel)
  1. Escolha a validade (30 a 365 dias) e, se quiser, os IPs que podem usá-la.
  2. Copie a chave (hys_theme_...). Ela aparece uma vez só: guarde como uma senha, num cofre ou nos segredos do CI.

2. Teste a chave

Terminal
export HYSTORE_THEME_TOKEN=hys_theme_...
curl https://theme.hystore.com.br/v1/me -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"
JSON
{
  "storeId": "0f558e5e-...",
  "store": { "name": "Minha Loja", "domain": "minhaloja.hystore.com.br" },
  "scopes": ["theme:read", "theme:write"],
  "credential": { "id": "...", "kind": "key" }
}

A loja é sempre a da chave: nenhuma rota recebe id de loja. Uma chave nunca faz mais do que o cargo de quem a criou permite, e revogar no painel corta na hora.

Ler o tema

Terminal
# Arquivos do rascunho, com sha256 e tamanho, e a revisão do rascunho
curl https://theme.hystore.com.br/v1/theme/files -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

# Um arquivo
curl "https://theme.hystore.com.br/v1/theme/file?path=sections/hero.liquid" -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

# Todos os arquivos de texto de uma vez (com conteúdo e hash)
curl https://theme.hystore.com.br/v1/theme/export -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

Um arquivo vem assim:

JSON
{ "path": "sections/hero.liquid", "content": "<section class=\"hero\">...", "sha256": "3f1c..." }

Gravar com segurança

Mande de volta o sha256 que você leu como baseSha:

Terminal
curl -X PUT "https://theme.hystore.com.br/v1/theme/file?path=sections/hero.liquid" \
  -H "Authorization: Bearer $HYSTORE_THEME_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"content":"<section class=\"hero\"><h1>{{ section.settings.title }}</h1></section>\n{% schema %}{\"name\":\"Hero\",\"settings\":[{\"id\":\"title\",\"type\":\"text\",\"label\":\"Título\"}]}{% endschema %}","baseSha":"3f1c..."}'
  • Se o arquivo mudou desde a sua leitura, a resposta é 409 com o hash atual, e nada é gravado. Leia de novo, junte e grave.
  • baseSha: null quer dizer que o arquivo ainda não pode existir (criar sem apagar o de alguém).
  • Sem baseSha, a gravação passa por cima.

Vários arquivos de uma vez, todos ou nenhum (até 100 mudanças):

Terminal
curl -X POST https://theme.hystore.com.br/v1/theme/files \
  -H "Authorization: Bearer $HYSTORE_THEME_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"changes":[{"path":"locales/pt.json","content":"{\"home\":{\"title\":\"Bem-vindo\"}}","baseSha":"9a0b..."},{"path":"sections/old.liquid","content":null}],"expectedRevision":12}'

content: null apaga. expectedRevision (opcional) recusa a gravação se outra passou na frente desde a sua leitura.

Um arquivo que quebra uma regra recebe 422 com cada problema:

JSON
{ "errors": [{ "code": "html_event_handler", "message": "Event attributes (onclick, onload...) are not allowed. Use data-hystore-* components.", "path": "sections/hero.liquid", "line": 3 }] }

Conferir, ver a prévia e publicar

Terminal
# Confere o rascunho inteiro
curl -X POST https://theme.hystore.com.br/v1/theme/check -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

# Link de 24 horas que abre o rascunho no endereço da loja
curl -X POST https://theme.hystore.com.br/v1/theme/preview -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

# Pede a publicação (alguém aprova no painel)
curl -X POST https://theme.hystore.com.br/v1/theme/publish-requests \
  -H "Authorization: Bearer $HYSTORE_THEME_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"note":"Banner da Black Friday"}'

Versões

Terminal
# As últimas 30 versões publicadas
curl https://theme.hystore.com.br/v1/theme/versions -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

# Um arquivo como estava na versão 3
curl "https://theme.hystore.com.br/v1/theme/versions/3/file?path=styles/theme.css" -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

# Traz a versão 3 de volta para o rascunho (a loja no ar não muda)
curl -X POST https://theme.hystore.com.br/v1/theme/versions/3/restore -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

Imagens e fontes

Terminal
# Lista, com o endereço público de cada uma
curl https://theme.hystore.com.br/v1/theme/assets -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

# Envia (o corpo é o arquivo; o tipo é lido do conteúdo)
curl -X PUT "https://theme.hystore.com.br/v1/theme/asset?path=assets/banner.webp" \
  -H "Authorization: Bearer $HYSTORE_THEME_TOKEN" \
  --data-binary @banner.webp

# Apaga
curl -X DELETE "https://theme.hystore.com.br/v1/theme/asset?path=assets/banner.webp" -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

Imagens PNG, JPEG, WebP, GIF e AVIF até 3 MB; fontes WOFF e WOFF2 até 1 MB. SVG não entra como arquivo de mídia.

Exemplo em Node.js

Troca um texto do tema e pede a publicação. Funciona no Node.js 18 ou mais novo, sem bibliotecas.

atualizar-titulo.mjsJavaScript
const API = 'https://theme.hystore.com.br/v1'
const headers = { Authorization: `Bearer ${process.env.HYSTORE_THEME_TOKEN}`, 'Content-Type': 'application/json' }

async function call(method, path, body) {
  const res = await fetch(API + path, { method, headers, body: body && JSON.stringify(body) })
  const data = await res.json()
  if (!res.ok) throw new Error(`${res.status} ${JSON.stringify(data.errors ?? data)}`)
  return data
}

// 1. Lê o arquivo de textos em português
const file = await call('GET', '/theme/file?path=locales/pt.json')
const texts = JSON.parse(file.content)

// 2. Muda o título e grava, com o hash lido (409 se alguém mudou antes)
texts.home = { ...texts.home, title: 'Temporada 5 chegou' }
await call('PUT', '/theme/file?path=locales/pt.json', { content: JSON.stringify(texts, null, 2), baseSha: file.sha256 })

// 3. Pede a publicação
await call('POST', '/theme/publish-requests', { note: 'Título da temporada 5' })
console.log('Pronto: aprove em Personalização > Tema em código.')
Terminal
HYSTORE_THEME_TOKEN=hys_theme_... node atualizar-titulo.mjs

Rotas

Rota Escopo
GET /v1/me qualquer
GET /v1/theme, GET /v1/theme/files, GET /v1/theme/file?path= read
GET /v1/theme/export read
PUT e DELETE /v1/theme/file?path=, POST /v1/theme/files write
POST /v1/theme/check read
POST /v1/theme/preview read
GET /v1/theme/versions, GET /v1/theme/versions/{n}/file?path= read
POST /v1/theme/versions/{n}/restore write
GET /v1/theme/assets, PUT e DELETE /v1/theme/asset?path= read, write
POST /v1/theme/publish-requests publish-request

Respostas de erro

Todo erro tem o mesmo formato e nunca traz detalhe interno:

JSON
{ "errors": [{ "code": "SCOPE_REQUIRED", "message": "This credential cannot do this (needs theme:write)." }] }
Status Quer dizer
400 pedido mal formado (caminho, corpo)
401 sem chave, chave errada, vencida ou revogada
403 a chave não tem o escopo, o IP não está na lista, o plano não tem o módulo, ou o pedido veio de uma página web
404 o arquivo ou a versão não existe
409 o arquivo ou o rascunho mudou desde a sua leitura
413 arquivo ou lote grande demais
422 o arquivo quebra uma regra do tema (com a linha)
429 muitas chamadas; espere os segundos de Retry-After

Limites

  • 120 leituras e 30 escritas por minuto por chave; acima disso, 429 com Retry-After.
  • Arquivos: 256 KB cada, 400 arquivos, 5 MB de texto. Mídia: imagens 3 MB, fontes 1 MB, 100 arquivos, 40 MB.