Documentación API
El Shoppi SDK, la API JSON y los TagCodes: todo lo que un partner necesita para construir sobre una tienda Shoppi.
Cómo funciona
Cada tienda en Shoppi Cloud se amplía con el Shoppi SDK, una librería JavaScript que la plataforma sirve en cada dominio alojado por Shoppi, y con los TagCodes, marcadores del lado del servidor que el motor de páginas resuelve antes de que la página llegue al navegador. Ambos hablan con la misma API JSON, que también se puede usar directamente.
- Sin claves API en el navegador. La tienda se reconoce por el dominio desde el que sale la petición: el SDK funciona en el dominio de la tienda sin secretos en el código.
- Los pagos pasan por Stripe. Las sesiones de checkout se crean en la cuenta Stripe del comerciante (Stripe Connect); Shoppi nunca retiene el dinero de sus clientes. Los reembolsos también pasan íntegramente por Stripe.
- Dos bases de datos. El catálogo se lee de la base de datos de Shoppi, la que el comerciante gestiona desde la app; cada dominio de tienda tiene además su propia base de datos. Tú eliges de cuál lee cada API (ver Catálogo). Las cuentas de clientes están siempre en la base de datos propia del dominio de la tienda, separadas de las demás tiendas.
- Versión actual del SDK: 2.9.0. Las respuestas tienen siempre la misma forma:
{"result": "ok" | "ko", "feedback": …}.
Instalación
Incluye el SDK una sola vez, en el <head> de la página. Al cargar crea el objeto global window.Shoppi.
<script>
window.ShoppiConfig = {
pageId: "%_ID%", // store id; the page engine fills it in (use %_ID% inside JS, not {id})
currency: "EUR", // default currency for cart and checkout
defaultLocale: "it", // language used when the URL has no /xx/ prefix
baseUrl: "", // leave empty: API calls go to the same origin
sources: "shoppi" // catalog database: "shoppi" (default) or "local"
};
</script>
<script src="/shoppi/shoppi-sdk.js?v=2.9.0"></script>
Todos los ajustes son opcionales: sin ShoppiConfig el SDK reconoce la tienda por el dominio y usa el euro. Sube el parámetro ?v= para que los navegadores descarguen un SDK más reciente.
Tienda y contenidos — Shoppi.site
| Método | Devuelve |
|---|---|
Shoppi.site.getInfo() |
Perfil de la tienda: nombre, logo, portada, descripción, categoría, ciudad, país, idioma. |
Shoppi.site.getPage(slug) |
Una página de contenido por su slug: título, contenido HTML y palabras clave, o null. |
Shoppi.site.getPages() |
Las secciones de la tienda: páginas de contenido y las categorías de los productos. |
Shoppi.site.getProducts(options) |
Igual que Shoppi.catalog.products(). |
Shoppi.site.getProduct(idOrSlug) |
Igual que Shoppi.catalog.product(). |
Shoppi.site.getCategories() |
Igual que Shoppi.catalog.categories(). |
Shoppi.site.search(q) / getSuggestions(q) |
Igual que Shoppi.catalog.search() y suggestions(). |
const info = await Shoppi.site.getInfo();
document.getElementById('store-name').textContent = info.title;
Catálogo — Shoppi.catalog
Productos, categorías, fotos y búsqueda: los datos que el comerciante gestiona en la app Shoppi, listos para construir un escaparate. Cada artículo llega con la misma forma, sea del tipo que sea:
{
id: 9610389, type: 'products', // products | services | files | offers
slug: 'curtirisorisobasmati2×500g',
title: 'Curtiriso Riso Basmati 2 × 500 g',
description: '', content: 'Basmati', // content may contain HTML
price: 4.79, currency: 'EUR', price_format: '4,79 €',
photo: 'https://storage.shoppi.app/…', photo_hires: '…', photos: ['…'],
quantity: 5, in_stock: true, ship_cost: 0, code: 'CX-DIS-000001',
category: 'Dispensa', keywords: ['dispensa'], link: '…', date: 1791312283
}
| Método | Devuelve |
|---|---|
Shoppi.catalog.products(options) |
Devuelve { items, count, limit, skip, hasMore }. Opciones: type (products, services, files, offers, all), limit (24), skip, sort (newest, updated, popular, price_asc, price_desc, title), category (id, slug o título), q, ids, inStock. |
Shoppi.catalog.product(idOrSlug, { type }) |
Un artículo, o null. Nunca se devuelve un artículo de otra tienda. |
Shoppi.catalog.categories({ type }) |
sections (por defecto: las categorías a las que se asignan los productos), albums o tree. |
Shoppi.catalog.category(ref) |
Una categoría por id, slug o título. |
photos(), pages(), page(slug), news(), videos() |
Los contenidos de la tienda. |
Shoppi.catalog.search(q, { type, limit, minPrice, maxPrice }) |
Devuelve { items, count, suggestions, did_you_mean }. |
Shoppi.catalog.suggestions(q) |
Títulos para un autocompletado. |
Shoppi.catalog.info() |
Perfil de la tienda. |
const page = await Shoppi.catalog.products({ limit: 12 });
const cats = await Shoppi.catalog.categories(); // [{ id: 600, slug: 'dispensa', title: 'Dispensa' }, …]
const food = await Shoppi.catalog.products({ category: 'dispensa' });
const one = await Shoppi.catalog.product(9610389); // or by slug
const hits = await Shoppi.catalog.search('riso'); // { items, count, suggestions }
Qué base de datos: por API, por llamada
'shoppi' (por defecto) lee la base de datos de Shoppi, donde el comerciante gestiona los productos desde la app. 'local' lee la base de datos propia del dominio de la tienda, vacía hasta que escribas en ella. Elige por API en ShoppiConfig.sources, en tiempo de ejecución con Shoppi.catalog.use() o para una sola llamada con { source }. Una fuente también puede ser la URL base de otro host o una función que devuelve tus propios datos. Carrito, checkout, cuentas de clientes y email funcionan siempre en el dominio de la tienda.
window.ShoppiConfig = {
pageId: "%_ID%",
sources: { products: 'shoppi', categories: 'local' } // or one value: 'local'
};
Shoppi.catalog.use('search', 'local'); // at runtime, one API
await Shoppi.catalog.products({ limit: 12 }, { source: 'local' }); // for one call
Renderizado y eventos
Shoppi.render(target, items, template) llena un elemento con una lista: la plantilla es una función, una cadena Handlebars o nada para la tarjeta integrada con su botón de añadir al carrito. Los elementos con data-shoppi-list se llenan solos al cargar la página; sus demás atributos data-shoppi-* son las opciones del método correspondiente. Eventos en document: shoppi:cart:added, shoppi:cart:updated, shoppi:checkout:started, shoppi:rendered.
const r = await Shoppi.catalog.products({ limit: 12 });
Shoppi.render('grid', r); // built-in card with add-to-cart button
Shoppi.render('grid', r, p => `<h3>${p.title}</h3><p>${p.price_format}</p>`);
<div data-shoppi-list="products" data-shoppi-limit="12" data-shoppi-category="dispensa">
<template><div class="card"><img src="{{photo}}"><h3>{{title}}</h3>
<button data-shoppi-add="{{id}}" data-shoppi-price="{{price}}"
data-shoppi-title="{{title}}" data-shoppi-image="{{photo}}">Add</button></div></template>
</div>
document.addEventListener('shoppi:cart:added', e => console.log(e.detail.title));
Carrito — Shoppi.cart
El carrito vive en el navegador (localStorage) y sobrevive a la recarga. Los precios y títulos que pases llegan hasta el checkout, así que indícalos siempre.
| Llamada | Qué hace |
|---|---|
Shoppi.cart.add(id, qty, { price, title, image }) |
Añade un producto (cantidad 1 por defecto). |
Shoppi.cart.updateQty(id, qty) |
Fija la cantidad; 0 quita la línea. |
Shoppi.cart.remove(id) |
Quita una línea. |
Shoppi.cart.clear() |
Vacía el carrito. |
Shoppi.cart.setCountry(code) |
Fija el país de envío (código ISO, por ejemplo 'IT'). |
Shoppi.cart.data |
Estado actual: { items, count, total, country }. |
Sin JavaScript, con atributos HTML:
<button data-shoppi-add="10034"
data-shoppi-price="29.90"
data-shoppi-title="Leather wallet"
data-shoppi-image="/img/wallet.jpg">Add to cart</button>
<span class="shoppi-cart-count"></span> <!-- item count, updated automatically -->
<span class="shoppi-cart-total"></span> <!-- total, formatted in the store currency -->
<select data-shoppi-country> <!-- shipping country -->
<option value="IT">Italia</option>
<option value="DE">Deutschland</option>
</select>
<button data-shoppi-checkout>Checkout</button>
Checkout — Shoppi.checkout
| Método | Qué hace |
|---|---|
Shoppi.checkout.start() |
Crea una sesión de Stripe Checkout para el carrito en la cuenta Stripe del comerciante y lleva al cliente a ella. |
Shoppi.checkout.startDirect(productId, metadata) |
Compra en un clic de un solo producto, sin carrito (servicios, reservas, descargas). |
Shoppi.checkout.createOnboardingLink() |
Devuelve el enlace de onboarding de Stripe de la tienda, para conectar o completar su cuenta Stripe. |
document.querySelector('#buy').addEventListener('click', () => Shoppi.checkout.start());
// Stripe onboarding for the merchant
const url = await Shoppi.checkout.createOnboardingLink();
window.location.href = url;
Cualquier botón con data-shoppi-checkout hace lo mismo que Shoppi.checkout.start(). Los costes de pago siguen el plan de la tienda: comisiones de Stripe más la tarifa de aplicación Shoppi Pay del 0,4 % + 1 céntimo por pago. Los reembolsos, totales o parciales, online o en el TPV, también pasan por Stripe.
Cuentas de clientes — Shoppi.user
Cuentas para los clientes de la tienda, guardadas en su base de datos. Tras el login, el token de sesión queda en el navegador y viaja con cada petición del SDK en la cabecera X-User-Token. Las cuentas están ligadas al dominio de la tienda: dos tiendas nunca ven los clientes de la otra.
| Método | Qué hace |
|---|---|
Shoppi.user.register(email, password, firstName, lastName) |
Crea una cuenta e inicia sesión. |
Shoppi.user.login(email, password) |
Inicia sesión. |
Shoppi.user.getProfile() |
Perfil del cliente conectado (null si no ha iniciado sesión). |
Shoppi.user.updateProfile(data) |
Actualiza campos del perfil, por ejemplo { phone }. |
Shoppi.user.saveAddress(type, address) |
Guarda una dirección; type es por ejemplo 'shipping'. |
Shoppi.user.logout() |
Cierra la sesión y recarga la página. |
Navegación y traducciones — Shoppi.router, Shoppi.lang
Las URL siguen el esquema /<language>/<page>, por ejemplo /it/contatti. Shoppi.router.navigate(slug, locale) carga una página sin recargar todo y la muestra en <main>; los enlaces con data-shoppi-link hacen lo mismo.
<a href="/it/contatti" data-shoppi-link="contatti">Contatti</a>
Shoppi.lang.load(locale) carga las traducciones de la tienda; Shoppi.lang.t(key, vars) devuelve un texto y sustituye los marcadores escritos como %_NAME%.
Directorio local — Shoppi.local
| Método | Devuelve |
|---|---|
Shoppi.local.getCities() |
Ciudades disponibles en el directorio local. |
Shoppi.local.getBusinesses(cityId, categoryId) |
Negocios de una ciudad, con filtro opcional por categoría. |
Email — Shoppi.mailer
Envía un email transaccional desde la tienda, por ejemplo desde un formulario de contacto. Límite: 10 emails al día por dispositivo.
await Shoppi.mailer.send({
to: '[email protected]',
subject: 'New request from the website',
body: '<p>Hello!</p>',
replyTo: '[email protected]' // optional
});
Shoppi.mailer.remaining(); // emails left today on this device
API JSON
Cada método del SDK es una llamada a la API JSON, que puedes usar directamente con Shoppi.call(endpoint, params, method) o con un simple fetch: el esquema es /api/<module>/<method>/json, en el dominio de la tienda.
| Endpoint | Para qué sirve |
|---|---|
GET /api/website/info/json |
Perfil de la tienda |
GET /api/website/section/json?clear_title=<slug> |
Página de contenido |
POST /api/checkout/createStripeSession/json |
Sesión de Stripe Checkout desde un carrito |
POST /api/checkout/startDirect/json |
Compra directa de un producto |
GET /api/checkout/createOnboardingLink/json |
Enlace de onboarding de Stripe |
POST /api/frontend_user/register/json |
Registro de cliente |
POST /api/frontend_user/login/json |
Login de cliente |
GET /api/local/getCities/json |
Directorio local: ciudades |
GET /api/website/products/json |
Productos (también listServices, listFiles, listOffers) |
GET /api/website/product/json?id= |
Un producto, por id o clear_title
|
GET /api/website/sections/json |
Secciones y categorías |
GET /api/website/listSells/json?parent= |
Artículos asignados a una sección |
GET /api/search/results/json?query= |
Búsqueda |
GET /api/search/suggestions/json?query= |
Autocompletado |
const res = await fetch('/api/website/info/json', { credentials: 'include' });
const data = await res.json(); // { "result": "ok", ... } or { "result": "ko", "feedback": "reason" }
Los endpoints del catálogo responden en el dominio de la tienda (su propia base de datos) y en https://shoppi.app (la base de datos de Shoppi). Para la fuente 'shoppi' el SDK llama a shoppi.app con el id de la tienda: un id que no pertenece al dominio que llama se rechaza. Shoppi.call(endpoint, params, method, { base }) elige el host.
Shoppi.call() devuelve la parte útil de una respuesta ok y lanza un Error con el mensaje feedback cuando la respuesta es ko.
TagCodes (lado servidor)
Los TagCodes son marcadores en las plantillas HTML de la tienda, resueltos en el servidor antes de enviar la página: el contenido está en el HTML que ven los buscadores.
| TagCode | Salida |
|---|---|
{css} / {js}
|
Hojas de estilo y scripts de la página y sus plugins |
{page_title}, {page_description}
|
Título y descripción SEO |
{page_name}, {page_logo}
|
Nombre y logo de la tienda |
{locale}, {currency}, {country}
|
Idioma, moneda y país del visitante |
{title}, {content}, {photo}, {price}, {link}
|
Campos del producto o artículo actual |
{cfield:title}, {cfield:description}, {cfield:cover}
|
Campos del perfil de la tienda |
{cart:act=drawer} |
Carrito lateral |
{search:nout=true} |
Búsqueda, inicializada sin salida por defecto |
{cookieconsent} |
Banner de consentimiento de cookies |
{offers:act=seo} |
Datos estructurados JSON-LD para productos |
Dentro de un objeto JavaScript usa %_ID% para el id de la tienda: allí las llaves se leerían como TagCode.
Acceso a archivos y datos
Los archivos de cada tienda son accesibles por WebDAV (también con la app de escritorio Shoppi Go) y los datos siguen siendo exportables: plantillas HTML estándar, la base de datos de la tienda y la API JSON de arriba. Las credenciales están en el panel de cuenta de la tienda.
¿Dudas o un caso que no aparece aquí? Reserva una llamada con el equipo de partners, o vuelve al kit de partners.