Ir al contenido

Tu primera llamada

Necesitas dos cosas: el token y el ID de un producto de la tienda. El ID de producto es el mismo que usa Tiendanube y está disponible en el template del tema como {{ product.id }}.

Ventana de terminal
curl https://sectionfy.codefy-apps.com/api/public/content/ndp_pub_a3f9k2mX7pLqR2wN/product/333333174

Tres piezas en esa URL:

SegmentoValorQué es
{token}ndp_pub_a3f9k2mX7pLqR2wNLa tienda.
{page}productEl tipo de página.
{targetId}333333174El producto concreto.

Ten en cuenta el vocabulario de {page}: cambia según lleve o no {targetId}. Con target se usa product / category; sin target se usa product-page / category-page / home-page. Es el error más común y no hay fallback: si los mezclas, la API responde 400. Está detallado en endpoints.

const TOKEN = window.SECTIONFY_TOKEN;
const API = 'https://sectionfy.codefy-apps.com/api/public/content';
const res = await fetch(`${API}/${TOKEN}/product/333333174`);
if (!res.ok) throw new Error(`Sectionfy ${res.status}`);
const bundle = await res.json();

No hace falta pasar headers, ni credentials: es un GET simple.

{
"page": "product",
"product_id": "333333174",
"sections": {
"faq-product-333333174-cmqic4kt5000ieq2bk3hbiat3": {
"titulo": "Preguntas frecuentes",
"items": [
{
"pregunta": "¿Hacen envíos a todo el país?",
"respuesta": "Sí, con despacho en 24 a 72 horas hábiles.",
"orden": 0
}
],
"estado": { "lifecycle": "active", "storefrontVisible": true },
"orden": 0
}
}
}

sections es un objeto, no un array. Cada clave codifica cuatro cosas separadas por guiones:

faq-product-333333174-cmqic4kt5000ieq2bk3hbiat3
└┬┘ └──┬──┘ └───┬───┘ └───────────┬────────────┘
│ │ │ └─ blockId: identidad estable de esta sección
│ │ └─ targetId: el producto (o el literal `general` si no aplica)
│ └─ placement: la página
└─ kind: el tipo de sección

Cada sección trae además un campo tipo con su identificador, así que quedarte con todos los FAQ son tres pasos: filtrar por tipo, aplicar la regla de render, y ordenar.

const faqs = Object.entries(bundle.sections)
// 1. El tipo que buscas, en MAYUSCULAS.
.filter(([, s]) => s.tipo === 'FAQ')
// 2. Regla de render: el bundle trae secciones ocultas y archivadas.
.filter(([, s]) => s.estado.lifecycle === 'active' && s.estado.storefrontVisible)
// 3. El comerciante define el orden arrastrando en el panel.
.sort(([, a], [, b]) => a.orden - b.orden)
.map(([key, seccion]) => ({ key, ...seccion }));

Esos tres pasos son iguales para todos los tipos, así que conviene envolverlos en un helper. En el resto de la documentación aparece como seccionesDeTipo(bundle, kind) y está escrito en el módulo cliente.

for (const faq of faqs) {
const detalles = faq.items
.slice()
.sort((a, b) => a.orden - b.orden)
.map(
(item) => `
<details>
<summary>${item.pregunta}</summary>
<p>${item.respuesta}</p>
</details>
`,
)
.join('');
contenedor.insertAdjacentHTML(
'beforeend',
`
<section>
${faq.titulo ? `<h2>${faq.titulo}</h2>` : ''}
${detalles}
</section>
`,
);
}

Eso es todo el ciclo. El resto de la documentación es detalle: qué otros endpoints hay, qué shape tiene cada tipo de sección, y cómo cachear bien.

El modelo mental — cuatro ideas que explican casi todas las decisiones de esta API.