developer.stockcito.com

Documentación para developers

Todo lo que necesitás para construir una App de Stockcito: manifiesto, permisos, Public API, extensiones de UI, automatizaciones y Marketplace — explicado de punta a punta, con ejemplos reales.

Introducción

Qué es una App de Stockcito

Una App es un servicio externo (tu propio servidor, en el lenguaje que quieras) que se conecta a la cuenta de un comercio de Stockcito para sumarle una función: leer sus pedidos y productos por una API, mostrar un panel propio dentro de su Dashboard, reaccionar automáticamente cuando pasa algo (Stockcito Flow), o agregar un módulo a su tienda online pública (DNA Modules).

Tu app nunca corre código dentro de Stockcito. Todo pasa por HTTP: Stockcito te llama a vos (webhooks, UI extensions, Flow actions) o vos llamás a Stockcito (Public API) usando un token que te entrega el comercio al instalarte. Todo request entre las dos partes va firmado con HMAC para que nadie pueda hacerse pasar por Stockcito ni por tu app.

Sin SDK obligatorio — HTTP + JSON alcanza
El comercio ve y aprueba cada permiso antes de instalar
Revisión humana antes de aparecer en el Marketplace
Apps gratis o de pago único, vos elegís

Empezar

Tu cuenta de developer

Es una cuenta separada de la cuenta de un comercio — nunca compartís login con la tienda que te instala.

1

Creá tu cuenta de developer

Registrate en /developers con tu email — no es lo mismo que crear una cuenta de comercio.

2

Registrá tu primera App

Nombre, descripción, categoría y la URL base de tu servidor (endpoints.baseUrl).

3

Escribí tu manifiesto

El JSON que declara qué puede hacer tu app (ver la sección El manifiesto más abajo).

4

Probala en una cuenta de prueba

Instalala en un comercio de prueba propio antes de mandarla a revisión para el Marketplace.

Desde tu panel de developer ves todas tus apps, y para cada instalación un resumen de entregas (webhooks enviados, si fallaron o no) — pero nunca el contenido de negocio del comercio (no ves sus ventas ni sus clientes reales, solo que "la entrega #123 a la instalación #45 falló con HTTP 500").

Referencia

El manifiesto

Un único JSON que describe todo lo que tu app declara: quién es, qué permisos pide, y qué extensiones ofrece.

{
  "key": "acme.puntos",
  "name": "Acme Puntos",
  "description": "Programa de puntos por compra",
  "category": "Crecimiento",
  "version": "1.0.0",
  "author": { "name": "Acme SRL", "url": "https://acme.dev" },
  "roles": ["owner", "admin"],
  "scopes": ["orders:read", "customers:read"],
  "events": ["order.paid"],
  "extensions": {
    "admin": ["dashboard.card"],
    "dna": [{ "key": "puntos-widget", "name": "Widget de puntos" }],
    "automationActions": [{ "key": "sumar_puntos", "name": "Sumar puntos" }]
  },
  "endpoints": {
    "baseUrl": "https://acme.dev",
    "webhookPath": "/webhook"
  }
}
keystring

Namespace único con un punto, ej. acme.puntos. Es tu identificador estable — no lo cambies entre versiones.

categoryenum

Una de: Escritorio, Comercio, Contenido, Crecimiento, Integraciones, Sistema.

rolesstring[]

Qué roles del comercio pueden instalar tu app: owner, admin, manager, cajero. Por defecto solo el dueño.

scopesstring[]

Los permisos que vas a usar en la Public API (ver la sección Scopes). Se muestran tal cual en la pantalla de consentimiento que ve el comercio antes de instalarte.

eventsstring[]

Eventos de webhook a los que te suscribís (order.created, order.paid, order.shipped, order.cancelled, product.published, inventory.low, customer.registered).

extensions.adminstring[]

Qué extensiones de UI vas a servir dentro del Dashboard: dashboard.card, order.sidebar, product.sidebar, customer.sidebar.

extensions.dnaobject[]

Módulos que tu app ofrece para insertar en la tienda pública del comercio (Studio → Diseño del inicio).

extensions.automationActionsobject[]

Acciones que Stockcito Flow puede invocar en tu servidor cuando el comercio arma una automatización.

endpoints.baseUrlurl

La raíz de tu servidor. Todo el resto de las rutas (webhook, UI, actions) se arman relativas a esta URL. Tiene que ser HTTPS pública — Stockcito rechaza IPs privadas o localhost por seguridad (anti-SSRF).

endpoints.webhookPathpath

Dónde recibís los eventos declarados en events. Default: /webhook.

Permisos

Scopes disponibles

orders:readVer pedidos
orders:writeCrear o modificar pedidos
products:readVer productos
products:writeCrear o modificar productos
customers:readVer clientes
customers:writeCrear o modificar clientes
inventory:readVer inventario
inventory:writeModificar inventario
sales:readVer ventas
sales:writeCrear o modificar ventas
shipping:readVer zonas de envío
shipping:writeModificar zonas de envío

Hoy los scopes de *:read son los que habilitan cada recurso de la Public API (ver más abajo). Los de *:write quedan declarados para uso futuro — pedilos solo si tu app realmente los necesita, ya que el comercio los ve todos en la pantalla de consentimiento antes de instalarte.

Flujo

Instalación y consentimiento

El comercio nunca instala tu app a ciegas — siempre ve una pantalla de consentimiento primero.

El dueño de la tienda pega la URL de tu manifiesto (o lo pega directo en JSON) en Configuración → Complementos. Stockcito lo descarga, lo valida, y le muestra tu nombre, descripción, versión y la lista de permisos en español simple — "esta app va a poder: ver pedidos, ver clientes" — antes de que confirme nada.

Al confirmar, Stockcito genera un token de acceso único para esa instalación y lo muestra una sola vez en pantalla. Ese es el token que el comercio (o vos, si tu app lo pide) usa como Authorization: Bearer <token> contra la Public API. Se guarda hasheado del lado de Stockcito — si se pierde, no hay forma de recuperarlo, solo reinstalar.

Referencia

Public API

Lecturas de solo lectura sobre los datos del comercio que te instaló, autenticadas por token.

Base URLurl

https://api.stockcito.com/api/public/v1

Authorizationheader

Bearer <token de la instalación> — el que se generó al instalarte.

Stockcito-Versionheader

Obligatorio en cada request, valor actual: 2026-09. Versionado por fecha para poder introducir cambios sin romper integraciones existentes.

Rate limitlímite

60 requests por minuto, por token (no por IP) — separado del límite general de la API.

Recursos disponibles (todos de solo lectura, paginados con page/perPage):

GET /productsproducts:read
GET /customerscustomers:read
GET /salessales:read
GET /inventoryinventory:read
GET /ordersorders:read
GET /returnsorders:read
GET /shippingshipping:read
curl "https://api.stockcito.com/api/public/v1/products?page=1&perPage=20" \
  -H "Authorization: Bearer TU_TOKEN" \
  -H "Stockcito-Version: 2026-09"

# {"data":[...], "total":123, "page":1, "perPage":20}

Referencia

Extensiones de UI

Tu app puede mostrar contenido propio dentro del Dashboard del comercio, sin escribir HTML/CSS/JS.

Si declarás dashboard.card en extensions.admin, Stockcito le hace un GET firmado a {baseUrl}/stockcito-ui/dashboard-card y renderiza lo que respondas como una tarjeta más en el Dashboard del comercio. Nunca mandás HTML: mandás un árbol de nodos declarativos, con enums cerrados, para que nunca puedas inyectar nada fuera de lo previsto.

// Tu servidor responde esto a GET /stockcito-ui/dashboard-card
{
  "type": "card",
  "title": "Puntos acumulados",
  "children": [
    { "type": "text", "value": "1.240 puntos activos", "weight": "bold" },
    { "type": "badge", "label": "+80 esta semana", "tone": "success" },
    { "type": "link", "label": "Ver detalle", "href": "https://acme.dev/panel" }
  ]
}

Nodos disponibles: text, badge, link, stack (agrupa en fila o columna) y card (anida los anteriores). Máximo 20 hijos por nivel y 20KB de respuesta — si tu servidor está caído, tarda demasiado, o responde algo inválido, Stockcito simplemente no muestra la tarjeta, nunca rompe el Dashboard del comercio.

Cada request firmado incluye X-Stockcito-Timestamp y X-Stockcito-Signature: sha256=..., calculada como HMAC-SHA256(tu_clave_de_firma, timestamp + "." + path). Verificala del lado del servidor y rechazá cualquier timestamp con más de 5 minutos de diferencia, para evitar ataques de repetición.

Verificar la firma en Node/Express:

const crypto = require("crypto")

const SIGNING_KEY = process.env.STOCKCITO_SIGNING_KEY // te lo dio Stockcito al instalarte
const TOLERANCE_SECONDS = 300

app.get("/stockcito-ui/dashboard-card", (req, res) => {
  const timestamp = req.header("X-Stockcito-Timestamp")
  const signatureHeader = req.header("X-Stockcito-Signature") || ""
  const path = req.path // "/stockcito-ui/dashboard-card"

  const now = Math.floor(Date.now() / 1000)
  if (!timestamp || Math.abs(now - Number(timestamp)) > TOLERANCE_SECONDS) {
    return res.status(401).send("Timestamp inválido o vencido")
  }

  const expected = crypto
    .createHmac("sha256", SIGNING_KEY)
    .update(`${timestamp}.${path}`)
    .digest("hex")

  // timingSafeEqual evita que un atacante deduzca la firma midiendo cuánto
  // tarda la comparación carácter por carácter.
  const received = signatureHeader.replace("sha256=", "")
  const valid =
    received.length === expected.length &&
    crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected))

  if (!valid) return res.status(401).send("Firma inválida")

  res.json({
    type: "card",
    title: "Puntos acumulados",
    children: [{ type: "text", value: "1.240 puntos activos", weight: "bold" }],
  })
})

Referencia

DNA Modules (Storefront)

Lo mismo que dashboard.card, pero para insertar contenido en la tienda pública del comercio.

Cada módulo que declarás en extensions.dna aparece como una opción para que el comercio lo agregue a su tienda desde el Studio (Diseño del inicio). Stockcito te pide el contenido en GET {baseUrl}/stockcito-ui/dna/{key} — mismo esquema de nodos y misma firma que dashboard.card — y lo cachea 60 segundos por comercio, porque acá el que ve el contenido es cualquier visitante anónimo de la tienda, no solo el dueño logueado.

Referencia

Flow Actions

Acciones que el comercio puede invocar automáticamente desde sus automatizaciones (Flow).

Cada acción en extensions.automationActions queda disponible para que el comercio arme una regla tipo "cuando pase X, hacé Y". Cuando se dispara, Stockcito te manda un POST firmado a {baseUrl}/stockcito-actions/{actionKey} con el payload del evento en el body.

POST /stockcito-actions/sumar_puntos
Content-Type: application/json
X-Stockcito-Timestamp: 1735689600
X-Stockcito-Signature: sha256=<hmac del body con tu clave>

{ "orderId": 4821, "total": 15400, "customerId": 92 }

Verificá la firma igual que en las extensiones de UI, pero acá el HMAC se calcula sobre timestamp + "." + body (el JSON completo, no un path). Respondé HTTP 2xx si todo salió bien. Si tu respuesta es un error, importa la diferencia: un HTTP 4xx/5xx transitorio (tu servidor caído un momento) hace que Stockcito reintente con backoff; un 2xx que vos mismo interpretás como "falla definitiva" de tu lado no debería devolverse como error HTTP, porque Stockcito no tiene forma de distinguir eso de un problema de red.

Servidor mínimo completo (Node, sin frameworks) — recibe la acción, verifica la firma sobre el body, y responde:

const http = require("http")
const crypto = require("crypto")

const SIGNING_KEY = process.env.STOCKCITO_SIGNING_KEY

http.createServer((req, res) => {
  if (req.method !== "POST" || req.url !== "/stockcito-actions/sumar_puntos") {
    res.writeHead(404).end()
    return
  }

  let body = ""
  req.on("data", (chunk) => { body += chunk })
  req.on("end", () => {
    const timestamp = req.headers["x-stockcito-timestamp"]
    const received = (req.headers["x-stockcito-signature"] || "").replace("sha256=", "")

    const expected = crypto
      .createHmac("sha256", SIGNING_KEY)
      .update(`${timestamp}.${body}`)
      .digest("hex")

    if (received.length !== expected.length || !crypto.timingSafeEqual(Buffer.from(received), Buffer.from(expected))) {
      res.writeHead(401).end("Firma inválida")
      return
    }

    const { orderId, total, customerId } = JSON.parse(body)
    // ... tu lógica: sumar puntos, crear el envío, lo que sea ...
    console.log(`Pedido ${orderId} de ${customerId} por $${total}`)

    res.writeHead(200, { "Content-Type": "application/json" })
    res.end(JSON.stringify({ ok: true }))
  })
}).listen(3000)

Distribución

Marketplace

Cómo publicar tu app para que cualquier comercio la encuentre y la instale con confianza.

1

Enviá tu app a revisión

Al crear o actualizar tu app en /developers, queda en estado "pendiente" — nunca se publica sola.

2

Un humano de Stockcito la revisa

Chequea que el manifiesto sea coherente con lo que la app dice hacer. Podés recibir un rechazo con motivo.

3

Se aprueba un snapshot

Lo que se instala es la versión aprobada (approvedManifest), nunca tu draft en edición — así una versión nueva en revisión no reemplaza silenciosamente lo que ya está instalado.

4

Le ponés precio (opcional)

Gratis, o un cobro único por instalación vía Mercado Pago Connect — hoy no hay suscripciones recurrentes de apps.

Para cobrar, conectás tu propia cuenta de Mercado Pago desde /developers (el mismo flujo de OAuth que usa un comercio para cobrar en su tienda, aplicado a vos como developer). Cuando alguien compra tu app, se le cobra con tu token de Mercado Pago — Stockcito se queda con un porcentaje como comisión de plataforma — y tu app queda desactivada hasta que el webhook de pago confirma que se acreditó.

Herramientas

SDK de TypeScript

Hay un SDK inicial en TypeScript (packages/sdk-ts) que tipa los recursos de la Public API. Todavía no está publicado en ningún registro público (npm) — por ahora, la forma soportada de integrarte es HTTP + JSON directo, documentado más arriba, que funciona igual desde cualquier lenguaje.

Buenas prácticas

Seguridad

HTTPS público obligatorio

Tu endpoints.baseUrl tiene que resolver a una IP pública. Stockcito rechaza localhost, IPs privadas (10.x, 192.168.x, etc.) y redirects — nunca vamos a llamar a algo dentro de tu red interna.

Verificá siempre la firma

Nunca proceses un webhook, UI fetch o Flow action sin validar X-Stockcito-Signature primero, con tu clave de firma exacta.

Rechazá timestamps viejos

Un timestamp con más de 5 minutos de diferencia respecto a tu reloj es sospechoso de replay — rechazalo aunque la firma sea válida.

Guardá tu token de acceso como secreto

El token de instalación de la Public API es equivalente a una contraseña de esa tienda — tratalo con el mismo cuidado que una clave de base de datos.

Soporte

Preguntas frecuentes

¿Necesito estar en el Marketplace para que un comercio use mi app?

No. Cualquier comercio puede instalar tu app pegando la URL de tu manifiesto o el JSON directamente, sin pasar por revisión. El Marketplace es para que comercios que no te conocen te encuentren, con la confianza extra de que Stockcito ya la revisó.

¿Puedo cambiar mi manifiesto sin que se rompa nada instalado?

Sí — lo que está instalado sigue usando la versión aprobada hasta que envíes una actualización y esa nueva versión pase su propia revisión.

¿Cómo prueba mi app un comercio de prueba?

Instalala igual que cualquier app, pegando el manifiesto directo (no hace falta esperar aprobación del Marketplace para probarla vos mismo).

¿Qué pasa si mi servidor está caído cuando Stockcito me llama?

Para UI extensions y DNA modules, simplemente no se muestra ese contenido — no rompe nada del lado del comercio. Para Flow Actions y webhooks, Stockcito reintenta con backoff exponencial durante un tiempo antes de darlo por definitivamente fallido.

Ir a tu panel de developer