Documentación para que POSFEL administre los productos, el stock, los pedidos y la factura FEL de una web hecha a mano. Empieza por Cómo funciona y sigue el índice de arriba hacia abajo; cada entrada es una sección completa con su propia dirección.
Tres actores: la tienda (dueño, en POSFEL), el integrador (IA o desarrollador, en el código de la web) y el comprador. Cinco piezas, cada una con un solo trabajo — si entiendes esta tabla, entiendes la integración.
Tu llave de sincronización. Se genera en POSFEL → Configuración → Integraciones → Web propia. Se muestra una sola vez; va en POSFEL_TOKEN, nunca en el código público.
El manifiesto de tu catálogo: productos, variantes, precios e imágenes. Lo genera tu IA leyendo el código de la web, o lo escribes a mano.
El CLI oficial: npx posfel-sync push sube el catálogo; status muestra el estado. También existe como archivo único descargable (sin npm).
Lo escribe el push: el mapeo de tus IDs a los productId/variantId de POSFEL que tu checkout necesita.
Alojado en POSFEL (forma 1) o el tuyo propio con la Storefront API (forma 2). En ambos la tarjeta se ingresa solo en la pasarela y la factura FEL sale sola.
No hace falta que escribas tú el manifiesto ni el checkout: la skill le da a la IA todo lo que necesita para hacerlo leyendo el código de tu web.
La skill contiene las instrucciones completas: cómo extraer el catálogo del código, el schema exacto del manifiesto, el checkout y el checklist final.
Lee https://posfel.com/integrations/skill-posfel-ecommerce.md y sigue esa skill para integrar esta web con POSFEL. Mi token de integración está en la variable POSFEL_TOKEN.
Lo único que la IA no puede hacer por ti es el paso 1 (el token lo genera el dueño de la tienda en POSFEL) y el paso 4 (la aprobación del sync). El resto lo resuelve con la skill y el CLI.
Lo hace el dueño de la tienda, en POSFEL. Es lo único que el integrador debe pedirle.
En POSFEL: Configuración → Integraciones → Web propia → Conectar. Ponle nombre y la URL de tu web, y copia el token — no volverá a mostrarse. Único requisito real de la tienda: una pasarela con el canal "Web propia" encendido (Stripe, Tilopay o CyberSource) en Configuración → Pagos. El marketplace público de posfel.com es opcional: tu web vende vía la integración aunque esté apagado.
# guárdalo fuera del control de versiones echo "pfi_TU_TOKEN" > .posfel-token echo ".posfel-token" >> .gitignore
pk_… del mismo modal sí es pública — esa es la que va en el navegador (paso 5, forma 2).Crea posfel-catalog.json en la raíz del proyecto. Es el contrato entre tu web y POSFEL.
Regla de oro: cada combinación vendible (color × talla) es una variante, y un producto con variantes no lleva precio ni stock propios. El externalId es tu identificador estable — no lo cambies entre syncs o se duplicarán productos.
{
"version": 1,
"site": { "name": "MI TIENDA", "url": "https://mitienda.com" },
"products": [
{
"externalId": "chaqueta-alpina",
"name": "Chaqueta Alpina Pro",
"description": "Chaqueta impermeable 3 capas…",
"images": ["https://mitienda.com/img/chaqueta.webp"],
"options": ["Color", "Talla"],
"variants": [
{ "externalId": "negro-s", "name": "Negro / S", "price": 189.0, "stock": 5,
"images": ["https://…/negro-frontal.webp", "https://…/negro-posterior.webp"] },
{ "externalId": "negro-m", "name": "Negro / M", "price": 189.0, "stock": 8 }
]
},
{ "externalId": "gorra", "name": "Gorra básica", "price": 79.0, "stock": 20, "images": ["https://…"] }
]
}price/stock/sku propios.price > 0 obligatorio.images del producto: URLs https públicas, fotos del producto (packshots) — nunca heros o banners del landing. La primera es la principal.images: [] (máx 5) — si hay foto frontal y posterior por color, ambas van en las images de cada variante de ese color, no revueltas en la galería del producto.stock: manda el inventario inicial REAL (pídeselo al dueño si la web no lo maneja) — con stock 0 el producto queda creado pero no comprable.publish: false si no quieres publicarlo al marketplace todavía.El push genera el ANÁLISIS — no aplica nada todavía.
POSFEL analiza el manifiesto (qué productos se crearían o actualizarían, con sus variantes y precios), valida la configuración de la tienda (pasarela, marketplace, FEL, tarifas de envío, Envia) y deja todo pendiente de aprobación. Cada error llega con su fix exacto.
$ POSFEL_TOKEN=pfi_TU_TOKEN npx posfel-sync@latest push ✔ Análisis listo — PENDIENTE DE APROBACIÓN Se crearían: 3 productos Variantes: 12 ⚠ Sin tarifas de envío nacionales Fix: Configura las tarifas por departamento en Configuración → Envíos. → El dueño debe APROBAR el sync en POSFEL → Integraciones # sin npm: curl -O https://posfel.com/integrations/posfel-sync.mjs → node posfel-sync.mjs push
Nada entra a la tienda sin la aprobación explícita del dueño.
En POSFEL la tarjeta Web propia muestra REVISAR SYNC PENDIENTE: el modal enseña exactamente qué propone la web (cada producto con su precio, acción CREAR/ACTUALIZAR y variantes), los errores del manifiesto con su corrección, y el checklist de configuración de la tienda.
npx posfel-sync status para escribir posfel.map.json con los IDs.Dos formas. En ambas nunca pongas un formulario de tarjeta: el pago siempre ocurre en la página de la pasarela. Y el marketplace público es opcional.
La más corta: el botón Pagar redirige al checkout de POSFEL con los IDs de posfel.map.json. POSFEL pide los datos del comprador, el NIT y el envío — y sus propias páginas de éxito y cancelación ya están resueltas. Incluye tu pk en el cart: así funciona aunque el marketplace público esté apagado.
function posfelCheckout(storeId, pk, items) { const cart = JSON.stringify({ storeId, pk, items }); location.href = "https://posfel.com/marketplace/checkout/multi?cart=" + encodeURIComponent(cart); } // producto con variantes ⇒ SIEMPRE productId + variantId posfelCheckout("cmb2xk4pq0003l70a", "pk_TU_CLAVE", [ { productId: "cm…shell", variantId: "cm…negroM", quantity: 1 } ]);
Con la Storefront API tu web conserva su carrito y su formulario (incluido el NIT/CF), y POSFEL pone las herramientas por detrás: catálogo y stock en vivo, tarifas de envío de tu tienda (nacionales y Envia.com con tu propia cuenta) y la creación del pago con regreso a tu web.
A · Genera el SDK con el CLI
Usa tu clave publicable pk_… (visible en POSFEL → Integraciones → Web propia → Gestionar — no es secreta, va en el JS del navegador). El CLI escribe posfel-storefront.js ya configurado con tu pk, tu moneda y los endpoints:
$ POSFEL_TOKEN=pfi_TU_TOKEN npx posfel-sync@latest sdk
✔ posfel-storefront.js escrito (moneda GTQ)B · Cablea tu checkout con window.POSFEL
// vitrina: precios y stock EN VIVO (y agotados deshabilitados) const cat = await POSFEL.catalog(); // checkout propio: tarifa de envío con las tarifas de TU tienda const envio = await POSFEL.quoteEnvio("GU", "Mixco"); // pagar: crea el pedido (valida y reserva stock) y redirige a la pasarela POSFEL.checkout({ items: [{ externalId: "chaqueta-alpina", variantExternalId: "negro-m", quantity: 1 }], buyer: { name, email, phone, nit }, // nit vacío = CF · phone con código de país shipping: { address, department: "GU", municipality: "Mixco" }, successUrl: location.origin + "/gracias.html", cancelUrl: location.origin + "/carrito.html" });
POSFEL.currency te dice la de tu tienda.successUrl/cancelUrl deben apuntar al dominio de la URL configurada en tu integración.POSFEL.geo() trae los departamentos y municipios oficiales (y los países del selector internacional) — arma selects con eso, nunca texto libre, o la tarifa no matchea.POSFEL.states(pais) y cotización en vivo con POSFEL.quoteEnvioIntl(items, destino) (cuenta Envia.com del vendedor).geo().countries (cada uno con dial), default geo().phonePrefix; buyer.phone viaja con el código ("+50255551234")./api/integrations/storefront/ — catalog · quote-shipping · checkout · order — todos con ?pk= y CORS.C · Las 2 páginas de retorno — éxito, rechazo y cancelación
El rechazo de tarjeta ocurre DENTRO de la pasarela (ahí mismo el comprador puede corregir y reintentar); tu web solo ve el desenlace por dos rutas, ambas con ?posfel_order=<id>. Nunca asumas éxito solo por llegar a la página de gracias.
// confirmFromUrl() espera solo mientras el pago siga "pending" // (el webhook de la pasarela tarda unos segundos más que el redirect) const o = await POSFEL.confirmFromUrl(); if (o?.paid) { vaciarCarrito(); // ÚNICO caso que vacía el carrito mostrarExito(o.orderId); } else if (o?.status === "pending") { mostrar("Estamos verificando tu pago…"); // + botón "Ver mi pedido" → o.portalUrl } else if (o) { // failed | cancelled | expired mostrar("El pago no se completó."); // + botón REINTENTAR → o.portalUrl }
// Aquí cae quien canceló o abandonó la pasarela. El carrito local // sigue INTACTO — no lo toques. Ofrece dos salidas: const id = new URLSearchParams(location.search).get("posfel_order"); if (id) { const o = await POSFEL.orderStatus(id); mostrarAviso("No completaste el pago", { reintentar: o.portalUrl, // paga el MISMO pedido (stock reservado 15 min) seguirComprando: "/carrito.html" // pagar de nuevo crea pedido nuevo }); }
o.portalUrl es la página del pedido en POSFEL: sabe reintentar el cobro del mismo pedido con la pasarela de la tienda, sin duplicar nada.expired) y libera el stock.orderStatus: pending · paid · failed · cancelled · expired — solo paid es venta.Lo que pasa después de que el comprador paga — sin que la web haga nada más.
El checkout reserva stock 15 minutos, cobra con la pasarela de la tienda y al confirmarse el pago: venta creada, factura FEL automática (el PDF viaja por WhatsApp y correo), stock descontado y pedido en Órdenes. Las devoluciones funcionan exactamente igual que las de una venta de mostrador: parciales o totales, anulación de FEL, reversión de stock por variante y reembolso por la pasarela.
POSFEL.catalog() o el feed google-merchant.xml.Las que definen quién manda sobre cada dato.
| REGLA | DETALLE |
|---|---|
| Stock | Solo se escribe al crear el producto. Después lo administra POSFEL (todas las ventas lo descuentan ahí) y un re-sync nunca lo pisa. |
| Precios y textos | En cada push, el manifiesto actualiza nombre, precio, imágenes y descripción (cuando viene). La web es la fuente de esos datos. |
| Campos omitidos | Omitir ≠ borrar: si generaste sku/barcode (etiquetas) o una descripción en POSFEL y el manifiesto no los trae, el push los conserva. |
| Bajas manuales | Un producto desactivado a mano en POSFEL no se reactiva: el push lo omite y lo reporta. Reactívalo en POSFEL o quítalo del manifiesto. |
| externalId | Estable entre syncs. Charset a-z A-Z 0-9 . _ - |, máx 120 caracteres. |
| removeMissing | true desactiva en POSFEL los productos/variantes que ya no vengan en el manifiesto. Default false. |
| Límites por sync | 500 productos · 100 variantes por producto · 10 imágenes por producto · 5 por variante · body 5 MB · 10 syncs cada 10 minutos. |
| Carrito | Todos los ítems de una misma tienda. Producto con variantes exige variantId. |
| Token | Secreto de servidor. Rotarlo invalida el anterior al instante. Eliminar la integración desconecta la web por completo — los productos y ventas importados se quedan en la tienda. |
Los cinco que resuelven el 95% de los tickets.
El header debe ser Authorization: Bearer pfi_… con el token vigente. Si lo rotaste o eliminaste la integración, genera uno nuevo en POSFEL → Integraciones → Web propia.
El producto se creó pero no es elegible para el marketplace (y por lo tanto para el checkout). Corrige la causa en el manifiesto (imagen https válida, stock > 0, precio > 0) y vuelve a correr el push.
Casi siempre es un producto con variantes al que le falta el variantId, un producto despublicado, o stock agotado. El checkout valida contra la base de datos de POSFEL, no contra tu HTML.
El precio real vive en POSFEL. Actualiza el manifiesto y corre posfel-sync push — el precio del HTML es solo decorativo.
Máximo 10 pushes cada 10 minutos por integración. Espera lo que indique el mensaje y reintenta.
Crea tu cuenta, genera el token en Integraciones y corre tu primer push.