HystoreWiki

3 min de lecturaVer en Markdown

API del tema

https://theme.hystore.com.br/v1 lee y cambia el tema en código de una tienda. Es la API que usa la herramienta hystore, abierta para tus integraciones y para CI. La lista completa de rutas, con sus formatos, está en la OpenAPI.

1. Crea una llave

  1. En el panel, abre Personalización > Acceso al tema > Crear llave.
  2. Dale un nombre (por ejemplo, Deploy del sitio).
  3. Elige lo que puede hacer:
Alcance Permite
theme:read leer archivos, versiones y medios; revisar; enlaces de vista previa
theme:write cambiar el borrador, imágenes y fuentes; traer una versión de vuelta
theme:publish-request pedir publicación (se aprueba en el panel)
  1. Elige cuánto dura (30 a 365 días) y, si quieres, las IP que pueden usarla.
  2. Copia la llave (hys_theme_...). Aparece una sola vez: guárdala como una contraseña, en un baúl o en los secretos del CI.

2. Prueba la llave

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": "Mi Tienda", "domain": "mitienda.hystore.com.br" },
  "scopes": ["theme:read", "theme:write"],
  "credential": { "id": "...", "kind": "key" }
}

La tienda es siempre la de la llave: ninguna ruta recibe id de tienda. Una llave nunca hace más de lo que permite el rol de quien la creó, y revocarla en el panel la corta al instante.

Leer el tema

Terminal
# Archivos del borrador, con sha256 y tamaño, y la revisión del borrador
curl https://theme.hystore.com.br/v1/theme/files -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

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

# Todos los archivos de texto de una vez (con contenido y hash)
curl https://theme.hystore.com.br/v1/theme/export -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

Un archivo viene así:

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

Escribir con seguridad

Devuelve el sha256 que leíste 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..."}'
  • Si el archivo cambió desde que lo leíste, la respuesta es 409 con el hash actual, y no se escribe nada. Lee de nuevo, junta y escribe.
  • baseSha: null quiere decir que el archivo todavía no puede existir (crear sin borrar el de otra persona).
  • Sin baseSha, la escritura pisa lo que haya.

Varios archivos de una vez, todos o ninguno (hasta 100 cambios):

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\":\"Bienvenido\"}}","baseSha":"9a0b..."},{"path":"sections/old.liquid","content":null}],"expectedRevision":12}'

content: null borra. expectedRevision (opcional) rechaza la escritura si otra pasó antes desde tu lectura.

Un archivo que rompe una regla recibe 422 con 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 }] }

Revisar, ver la vista previa y publicar

Terminal
# Revisa el borrador entero
curl -X POST https://theme.hystore.com.br/v1/theme/check -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

# Enlace de 24 horas que abre el borrador en la dirección de la tienda
curl -X POST https://theme.hystore.com.br/v1/theme/preview -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

# Pide la publicación (alguien aprueba en el panel)
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 de Black Friday"}'

Versiones

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

# Un archivo como estaba en la versión 3
curl "https://theme.hystore.com.br/v1/theme/versions/3/file?path=styles/theme.css" -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

# Trae la versión 3 de vuelta al borrador (la tienda en el aire no cambia)
curl -X POST https://theme.hystore.com.br/v1/theme/versions/3/restore -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

Imágenes y fuentes

Terminal
# Las lista, con la dirección pública de cada una
curl https://theme.hystore.com.br/v1/theme/assets -H "Authorization: Bearer $HYSTORE_THEME_TOKEN"

# Envía (el cuerpo es el archivo; el tipo se lee del contenido)
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

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

Imágenes PNG, JPEG, WebP, GIF y AVIF hasta 3 MB; fuentes WOFF y WOFF2 hasta 1 MB. SVG no entra como archivo de medios.

Ejemplo en Node.js

Cambia un texto del tema y pide la publicación. Funciona en Node.js 18 o más nuevo, sin bibliotecas.

actualizar-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. Lee el archivo de textos en español
const file = await call('GET', '/theme/file?path=locales/es.json')
const texts = JSON.parse(file.content)

// 2. Cambia el título y escribe, con el hash leído (409 si alguien lo cambió antes)
texts.home = { ...texts.home, title: 'Llegó la temporada 5' }
await call('PUT', '/theme/file?path=locales/es.json', { content: JSON.stringify(texts, null, 2), baseSha: file.sha256 })

// 3. Pide la publicación
await call('POST', '/theme/publish-requests', { note: 'Título de la temporada 5' })
console.log('Listo: apruébalo en Personalización > Tema en código.')
Terminal
HYSTORE_THEME_TOKEN=hys_theme_... node actualizar-titulo.mjs

Rutas

Ruta Alcance
GET /v1/me cualquiera
GET /v1/theme, GET /v1/theme/files, GET /v1/theme/file?path= read
GET /v1/theme/export read
PUT y 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 y DELETE /v1/theme/asset?path= read, write
POST /v1/theme/publish-requests publish-request

Respuestas de error

Todo error tiene el mismo formato y nunca trae detalles internos:

JSON
{ "errors": [{ "code": "SCOPE_REQUIRED", "message": "This credential cannot do this (needs theme:write)." }] }
Estado Quiere decir
400 pedido mal formado (ruta, cuerpo)
401 sin llave, llave equivocada, vencida o revocada
403 la llave no tiene el alcance, la IP no está en la lista, el plan no tiene el módulo, o el pedido vino de una página web
404 el archivo o la versión no existe
409 el archivo o el borrador cambió desde tu lectura
413 archivo o lote demasiado grande
422 el archivo rompe una regla del tema (con la línea)
429 demasiadas llamadas; espera los segundos de Retry-After

Límites

  • 120 lecturas y 30 escrituras por minuto por llave; arriba de eso, 429 con Retry-After.
  • Archivos: 256 KB cada uno, 400 archivos, 5 MB de texto. Medios: imágenes 3 MB, fuentes 1 MB, 100 archivos, 40 MB.