Saltar al contenido
Tienda online

Menús y contenido

Arma la navegación y las páginas de contenido de tu tienda headless.

Vas a armar la base de una tienda de Lima: el menú del encabezado, la categoría «Polos» y la página «Envíos». Todo con Storefront API, sin token.

Requisitos

  • El slug o un dominio de la tienda, para x-Store-Domain. Ver Tienda headless.
  • Categorías y páginas publicadas en la tienda.

Lee la configuración

GET /v1/settings trae en una llamada la tienda, su marca, su SEO, sus páginas publicadas (cms.pages) y sus menús activos (cms.menus). Pídela una vez por petición y reutilízala. GET /v1/site-settings trae solo cms.settings.

curl https://storefront.ecomiq.pe/v1/settings \
  -H "x-Store-Domain: mi-tienda"
Respuesta (extracto)
{
  "store": { "name": "Mi tienda", "currency": "PEN", "visibility": "public" },
  "cms": {
    "settings": {
      "branding": { "logoUrl": "https://…/logo.webp" },
      "seo": { "siteName": "Mi tienda", "robotsIndex": true },
      "contact": { "whatsapp": "+51987654321" }
    }
  }
}

Los pasos siguientes reutilizan API y headers.

  • Con visibility: "private", la tienda pide contraseña. Ver Abre una tienda privada.
  • Con robotsIndex: false, bloquea todo el sitio en robots.txt.

Pinta el menú

Los menús llegan en cms.menus y en GET /v1/menus. Para uno solo, usa GET /v1/menus/{key}. Una tienda nueva trae main, footer y account.

curl https://storefront.ecomiq.pe/v1/menus/main \
  -H "x-Store-Domain: mi-tienda"
Respuesta (extracto)
{
  "key": "main",
  "name": "Menú principal",
  "items": [
    {
      "label": "Polos",
      "url": "/categories/polos",
      "reference": { "type": "category", "id": "7204558912004327982" },
      "order": 1,
      "visible": true,
      "children": []
    }
  ]
}
  • Los ítems llegan tal como se guardaron. Omite los que tienen visible: false y ordena por order, también en children.
  • Los enlaces a productos y categorías llegan con su URL actual, aunque el comercio la cambie. reference dice a cuál apuntan.

Muestra una categoría

GET /v1/categories/{slug} trae la categoría con su SEO, sus migas de pan y sus subcategorías. Luego pide sus productos con categoryId, como en Tienda headless.

curl https://storefront.ecomiq.pe/v1/categories/polos \
  -H "x-Store-Domain: mi-tienda"

curl "https://storefront.ecomiq.pe/v1/products?categoryId=7204558912004327982" \
  -H "x-Store-Domain: mi-tienda"
Respuesta de la categoría (extracto)
{
  "id": "7204558912004327982",
  "name": "Polos",
  "url": "/categories/polos",
  "metaTitle": "Polos de algodón pima",
  "productCount": 24,
  "ancestors": [
    {
      "id": "7204558912004329210",
      "name": "Hombre",
      "url": "/categories/hombre"
    }
  ],
  "children": []
}
  • ancestors va de la raíz al padre. categoryId excluye las subcategorías.
  • GET /v1/categories trae todas en una lista plana, ordenada por order. Arma el árbol con parentId. GET /v1/brands lista las marcas.
  • GET /v1/collections lista las colecciones. Para una, usa GET /v1/collections/{slug} y collectionId. Sin sort, los productos siguen el orden que eligió el comercio.

Muestra páginas y artículos

GET /v1/pages/{slug} trae la versión publicada de una página. Todas llegan también en cms.pages.

curl https://storefront.ecomiq.pe/v1/pages/envios \
  -H "x-Store-Domain: mi-tienda"
Respuesta (extracto)
{
  "name": "Envíos",
  "slug": "envios",
  "layout": "content",
  "settings": {
    "title": "Envíos",
    "html": "<p>Entregamos en Lima en 24 a 48 horas.</p>",
    "seo": { "title": "Envíos", "description": "Tiempos y costos de envío." }
  },
  "sections": []
}
  • Con layout: "content", el texto viene en settings: title, html y seo. La portada tiene el slug home y trae sections con sus blocks.
  • html lo escribe el comercio. Sanéalo antes de insertarlo.

Para el blog, GET /v1/articles lista los artículos publicados, del más reciente al más antiguo. GET /v1/articles/{slug} trae uno con su body en HTML, que también debes sanear.

curl "https://storefront.ecomiq.pe/v1/articles?tag=pima&limit=12" \
  -H "x-Store-Domain: mi-tienda"

Filtra con folder o tag, por valor exacto, o con search, que busca en el título y el resumen. limit va de 1 a 100 y vale 24; no hay más páginas.

Agrega el buscador

GET /v1/search/autocomplete sugiere productos mientras el comprador escribe. Envía search, de 2 a 80 caracteres, y limit, de 1 a 20.

curl "https://storefront.ecomiq.pe/v1/search/autocomplete?search=polo&limit=6" \
  -H "x-Store-Domain: mi-tienda"
Respuesta (extracto)
[
  {
    "name": "Polo pima azul",
    "url": "/products/polo-pima-azul",
    "imageUrl": "https://…/polo.webp"
  }
]

Para la página de resultados, usa GET /v1/products?search=polo.

Resuelve una URL

Antes de pintar una ruta, revisa si el comercio la redirigió.

curl "https://storefront.ecomiq.pe/v1/redirects/resolve?path=/ofertas" \
  -H "x-Store-Domain: mi-tienda"
Respuesta
{
  "redirect": {
    "location": "/categories/polos",
    "statusCode": 301,
    "preserveQuery": true
  }
}

Responde con statusCode y location. Con preserveQuery: true, agrega la query de la petición. Sin redirección, redirect es null. La ruta debe coincidir exacta, mayúsculas incluidas; solo se ignora la / final.

Luego, en tu ruta comodín, pregunta qué hay en esa ruta. Envía solo la ruta, sin dominio ni query.

curl "https://storefront.ecomiq.pe/v1/urls/resolve?path=/categories/polos" \
  -H "x-Store-Domain: mi-tienda"
Respuesta (extracto)
{
  "kind": "category",
  "url": "/categories/polos",
  "handle": "polos",
  "product": null,
  "category": { "id": "7204558912004327982", "name": "Polos" }
}
  • product o category: pinta la ficha o la categoría con el objeto que llega.
  • redirect: responde 301 a url. Pasa con URLs viejas, en mayúsculas o con / al final.
  • Solo resuelve productos y categorías. Si nada coincide: 404 Url.NotFound.

Si guardas enlaces a productos o categorías en tu propio contenido, POST /v1/urls/links los devuelve con su URL actual y su reference, en el mismo orden. Acepta hasta 100, conserva la query y deja igual los externos.

curl -X POST https://storefront.ecomiq.pe/v1/urls/links \
  -H "x-Store-Domain: mi-tienda" \
  -H "Content-Type: application/json" \
  -d '{ "links": [{ "url": "/products/polo-azul?talla=m" }] }'

Publica el sitemap

GET /v1/sitemap lista las URL canónicas de productos visibles, categorías y colecciones. Cada página trae hasta 1000 productos; la primera suma las categorías y las colecciones.

curl "https://storefront.ecomiq.pe/v1/sitemap?page=1" \
  -H "x-Store-Domain: mi-tienda"
Respuesta (extracto)
{
  "items": [{ "url": "/categories/polos", "updatedOn": null }],
  "nextPage": 2,
  "totalPages": 3
}

Las URL son rutas: antepón el dominio de tu tienda. No incluye la portada, las páginas ni el blog; agrégalos desde cms.pages y GET /v1/articles. Si totalPages es mayor que 1, publica un índice con un sitemap por página.

Muestra las tiendas físicas

GET /v1/store-locations lista las tiendas físicas activas, por nombre. Filtra con search por nombre o ciudad. Trae 20 por defecto; usa limit y cursor para pedir más. En un marketplace trae las de la tienda principal; las de un vendedor salen con sellerId. GET /v1/store-locations/{id} trae una.

curl "https://storefront.ecomiq.pe/v1/store-locations?search=Miraflores" \
  -H "x-Store-Domain: mi-tienda"
Respuesta (extracto)
{
  "data": [
    {
      "name": "Tienda Miraflores",
      "address": "Av. Larco 1234",
      "city": "Lima",
      "schedules": [
        {
          "dayOfWeek": "monday",
          "openTime": "10:00:00",
          "closeTime": "21:00:00"
        }
      ]
    }
  ],
  "hasNextPage": false,
  "nextCursor": null
}

Abre una tienda privada

Una tienda con visibility: "private" responde 401 con Common.Unauthorized en todas las llamadas, salvo /v1/settings y /v1/access/unlock. Pide la contraseña al visitante y envíala desde tu servidor.

curl -X POST https://storefront.ecomiq.pe/v1/access/unlock \
  -H "x-Store-Domain: mi-tienda" \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{ "accessKey": "<contraseña>" }'

Responde { "unlocked": true } y deja la cookie ecomiq_store_access, válida por 12 horas. Reenvíala en cada llamada siguiente; en cURL, con -b cookies.txt. Si el comercio cambia la contraseña, la cookie deja de valer.

Errores

codeEstadoQué hacer
Url.NotFound404No hay nada publicado en esa ruta. Muestra tu página 404.
cms.page.not_found404La página no existe o no está publicada.
cms.article.not_found404El artículo no existe o no está publicado.
Category.NotFound404La categoría no existe o está inactiva.
cms.menu.not_found404El menú no existe o está inactivo. Pinta el encabezado sin él.
Common.NotFound404No existe la colección, la ubicación o la tienda.
Common.Validation400Revisa errors. Por ejemplo, search con un solo carácter.
Common.Unauthorized401La tienda es privada. Pide la contraseña.
Store.AccessDenied401La contraseña no coincide.
Common.ServiceUnavailable503El buscador no responde. Reintenta en unos segundos.

Siguientes pasos

Última actualización:

En esta página