Storefront API — Referencia Completa
Documentación para desarrolladores que construyen frontends custom (React, Next.js, etc.) sobre Demosle CMS.
Configuración base#
Todos los endpoints son públicos salvo los marcados con Requiere auth Requiere autenticación (Customer JWT).
BASE_URL: https://api.tudominio.com
Content-Type: application/json
X-Tenant-Slug: {tu-tenant-slug} ← requerido en todos los requests
Para endpoints autenticados, incluir el token en el header:
Authorization: Bearer {customer_jwt}
Notas generales#
- Caché: Endpoints públicos tienen caché del lado del servidor (TTLs detallados por endpoint).
- Rate limiting: El endpoint de checkout tiene límite de llamadas propio.
- Tenant: El middleware resuelve automáticamente el tenant desde el dominio o el header
X-Tenant-Slug. - Errores estándar:
400— Validación fallida (body inválido, campo faltante)401— JWT inválido o expirado404— Recurso no existe o no publicado410— Recurso ya fue procesado (ej: carrito abandonado ya recuperado)500— Error interno del servidor
1. Sitio#
GET/api/storefront/site#
Configuración general del sitio: marca, módulos activos, analytics.
Caché: 1 hora.
Respuesta:
{
"success": true,
"data": {
"site": {
"name": "string",
"logo": "string | null",
"favicon": "string | null",
"primaryColor": "#hex",
"secondaryColor": "#hex"
},
"business": {
"email": "string | null",
"phone": "string | null",
"address": "string | null",
"socialLinks": {
"facebook": "string | null",
"instagram": "string | null",
"twitter": "string | null",
"linkedin": "string | null"
}
},
"modules": {
"ecommerce": true,
"blog": true,
"portfolio": true
},
"store": {
"businessType": "PRODUCTS | SERVICES | EXPERIENCES",
"enabledProductTypes": ["PHYSICAL_PRODUCT", "DIGITAL_PRODUCT", "SERVICE", "EXPERIENCE"],
"checkoutEnabled": true
},
"analytics": {
"ga4Id": "string | null",
"gtmId": "string | null",
"metaPixelId": "string | null",
"tiktokPixelId": "string | null",
"manyChatId": "string | null"
},
"siteContent": {
"banners": [],
"hero": {},
"about": {},
"gallery": [],
"schedule": [],
"popup": { "active": false }
}
}
}
GET/api/storefront/site/navigation#
Menú de navegación configurado por el tenant.
Respuesta:
{
"success": true,
"data": {
"navigation": [
{
"id": "string",
"label": "string",
"url": "string",
"type": "internal | external",
"children": []
}
]
}
}
2. Secciones del sitio#
GET/api/storefront/site-sections#
Secciones configurables del sitio (hero, features, CTA, testimonials, FAQ, etc.).
Caché: 1 hora.
Query params:
| Param | Tipo | Descripción |
|---|---|---|
key | string | Filtra por slug de sección específica |
Respuesta (sin key):
{
"success": true,
"sections": [
{
"key": "hero",
"type": "string",
"name": "string",
"data": {}
}
]
}
Respuesta (con key):
{
"success": true,
"section": { "key": "hero", "type": "...", "name": "...", "data": {} }
}
3. Páginas estáticas#
GET/api/storefront/pages/:slug#
Respuesta:
{
"success": true,
"data": {
"page": {
"id": "string",
"title": "string",
"slug": "string",
"content": {},
"excerpt": "string",
"featuredImage": "string | null",
"seoTitle": "string | null",
"seoDescription": "string | null",
"publishedAt": "ISO date"
}
}
}
4. Productos#
GET/api/storefront/products#
Lista de productos. Caché: 30 min (variable según params).
Query params:
| Param | Tipo | Descripción |
|---|---|---|
page | number | Default: 1 |
limit | number | Default: 20 |
categoryId | string | Filtrar por categoría |
categorySlug | string | Filtrar por slug de categoría |
featured | true|false | Solo destacados |
search | string | Búsqueda por nombre |
tagSlug | string | Filtrar por tag |
sort | string | price-asc, price-desc, name, newest |
Respuesta:
{
"success": true,
"products": [
{
"id": "string",
"name": "string",
"slug": "string",
"shortDescription": "string",
"type": "PHYSICAL_PRODUCT | DIGITAL_PRODUCT | SERVICE | EXPERIENCE",
"price": 19990,
"comparePrice": 29990,
"stock": 10,
"trackStock": true,
"images": ["https://..."],
"featured": true,
"requiresScheduling": false,
"categoryId": "string",
"category": { "id": "string", "name": "string", "slug": "string" },
"tags": [{ "id": "string", "name": "string", "slug": "string", "color": "#hex", "icon": "string" }],
"createdAt": "ISO date",
"imageUrl": "string | null"
}
],
"pagination": { "page": 1, "limit": 20, "total": 100, "totalPages": 5 }
}
GET/api/storefront/products/featured#
Productos destacados. Caché: 30 min.
Query params:
| Param | Tipo | Descripción |
|---|---|---|
limit | number | Default: 8 |
Respuesta: igual a productos pero sin paginación.
GET/api/storefront/products/search#
Búsqueda avanzada con filtros de precio y stock.
Query params:
| Param | Tipo | Descripción |
|---|---|---|
q | string | Query de búsqueda |
category | string | Filtrar por categoría |
minPrice | number | Precio mínimo |
maxPrice | number | Precio máximo |
inStock | true|false | Solo con stock |
featured | true|false | Solo destacados |
page | number | |
limit | number | |
sortBy | string |
GET/api/storefront/products/:slug#
Detalle de producto. Caché: 30 min.
Respuesta:
{
"success": true,
"product": {
"id": "string",
"name": "string",
"slug": "string",
"description": "string",
"shortDescription": "string",
"type": "PHYSICAL_PRODUCT | DIGITAL_PRODUCT | SERVICE | EXPERIENCE",
"price": 19990,
"comparePrice": 29990,
"sku": "string",
"stock": 10,
"trackStock": true,
"images": ["https://..."],
"files": [],
"featured": true,
"requiresScheduling": false,
"seoTitle": "string",
"seoDescription": "string",
"category": { "id": "string", "name": "string", "slug": "string" },
"tags": [],
"variants": [
{ "id": "string", "name": "string", "stock": 5, "price": 19990, "attributes": {} }
],
"createdAt": "ISO date",
"imageUrl": "string | null",
"promotions": [
{
"id": "string",
"name": "string",
"description": "string",
"type": "PERCENTAGE | FIXED_AMOUNT | FREE_SHIPPING | QUANTITY_DISCOUNT | BUY_X_GET_Y",
"value": 10,
"scope": "STORE_WIDE | CATEGORY | PRODUCT"
}
],
"bestPromotion": {
"name": "string",
"type": "string",
"discountAmount": 2000,
"finalPrice": 17990
}
},
"relatedProducts": [
{
"id": "string",
"name": "string",
"slug": "string",
"shortDescription": "string",
"price": 15000,
"comparePrice": null,
"stock": 3,
"trackStock": true,
"images": ["https://..."],
"imageUrl": "string | null"
}
]
}
5. Categorías#
GET/api/storefront/categories#
Respuesta:
{
"success": true,
"categories": [
{
"id": "string",
"name": "string",
"slug": "string",
"description": "string | null",
"image": "string | null",
"parentId": "string | null",
"_count": { "products": 12 }
}
]
}
6. Experiencias#
GET/api/storefront/experiences#
Query params:
| Param | Tipo | Descripción |
|---|---|---|
page | number | Default: 1 |
limit | number | Default: 20 |
categoryId | string | |
experienceType | string | |
location | string | |
search | string | |
featured | true|false |
Respuesta:
{
"success": true,
"experiences": [
{
"id": "string",
"name": "string",
"slug": "string",
"description": "string",
"shortDescription": "string",
"price": 25000,
"images": ["https://..."],
"categoryId": "string",
"featured": false,
"createdAt": "ISO date",
"imageUrl": "string | null",
"translations": [{ "language": "es", "name": "string" }]
}
],
"pagination": { "page": 1, "limit": 20, "total": 5, "totalPages": 1 }
}
GET/api/storefront/experiences/:slug#
Respuesta adicional (incluye slots disponibles):
{
"success": true,
"experience": {
"...campos base...",
"availableSlots": [
{
"id": "string",
"startDateTime": "ISO date",
"endDateTime": "ISO date",
"capacity": 10,
"bookedCount": 3,
"price": 25000,
"availableCapacity": 7
}
]
}
}
GET/api/storefront/experiences/:id/slots#
Slots de disponibilidad de una experiencia.
Query params:
| Param | Tipo | Descripción |
|---|---|---|
startDate | ISO date | Default: ahora |
endDate | ISO date | Default: +60 días |
7. Blog#
GET/api/storefront/posts#
Query params:
| Param | Tipo | Descripción |
|---|---|---|
page | number | |
limit | number | |
categoryId | string | |
search | string |
GET/api/storefront/posts/:slug#
GET/api/storefront/post-categories#
8. Portfolio / Proyectos#
GET/api/storefront/projects#
Query params:
| Param | Tipo | Descripción |
|---|---|---|
page | number | Default: 1 |
limit | number | Default: 12 |
category | string | categoryId |
search | string |
GET/api/storefront/projects/:slug#
Respuesta adicional: incluye relatedProjects.
9. Sellers (Marketplace)#
GET/api/storefront/sellers#
Lista de vendedores activos. Caché: 30 min.
Respuesta:
{
"success": true,
"sellers": [
{
"id": "string",
"name": "string",
"slug": "string",
"email": "string",
"phone": "string | null",
"logo": "string | null",
"description": "string | null",
"_count": { "products": 15 }
}
]
}
GET/api/storefront/sellers/:slug#
Detalle de un seller.
GET/api/storefront/sellers/:slug/products#
Productos de un seller.
Query params:
| Param | Tipo |
|---|---|
page | number |
limit | number |
10. Directorio#
GET/api/storefront/directory#
Query params:
| Param | Tipo |
|---|---|
categoryId | string |
featured | true|false |
search | string |
page | number (default: 1) |
limit | number (default: 20) |
Respuesta:
{
"entries": [
{
"id": "string",
"name": "string",
"address": "string | null",
"description": "string | null",
"featured": false,
"active": true,
"category": { "id": "string", "name": "string", "slug": "string" }
}
],
"total": 20,
"page": 1,
"totalPages": 2
}
GET/api/storefront/directory/categories#
GET/api/storefront/directory/:slug#
11. Búsqueda#
GET/api/storefront/search#
Query params:
| Param | Tipo |
|---|---|
q | string (requerido) |
page | number |
limit | number |
sortBy | string |
GET/api/storefront/search/suggestions#
Query params: q (requerido), limit.
GET/api/storefront/search/popular#
Query params: limit.
12. Checkout#
POST/api/storefront/checkout/cart/calculate#
Calcula totales del carrito con cupones y envío.
Body:
{
"items": [
{ "productId": "string", "quantity": 2 }
],
"couponCode": "DESCUENTO20",
"shippingZoneId": "string"
}
Respuesta:
{
"success": true,
"cart": {
"items": [
{
"productId": "string",
"name": "string",
"image": "string | null",
"price": 19990,
"quantity": 2,
"subtotal": 39980
}
],
"subtotal": 39980,
"discount": 7996,
"shipping": 3990,
"total": 35974,
"coupon": {
"code": "DESCUENTO20",
"type": "PERCENTAGE",
"value": 20,
"discount": 7996
},
"promotions": [],
"shippingInfo": {
"zoneId": "string",
"zoneName": "Región Metropolitana",
"price": 3990,
"deliveryDays": "3-5 días hábiles",
"freeFromPromotion": false
}
}
}
GET/api/storefront/checkout/payment-methods#
Métodos de pago activos del tenant. Caché: 1 hora.
Respuesta:
{
"success": true,
"paymentMethods": [
{
"id": "string",
"provider": "MERCADOPAGO | FLOW | BANK_TRANSFER | KHIPU | KLAP | PAYKU",
"displayName": "string",
"logo": "string | null",
"description": "string",
"info": "string",
"bankDetails": {
"bankName": "string",
"accountType": "string",
"accountNumber": "string",
"accountHolder": "string",
"rut": "string",
"email": "string",
"instructions": "string"
}
}
]
}
POST/api/storefront/checkout/checkout#
Crea una orden y genera el link de pago.
⚠️ Rate limited. No usar para pruebas en loop.
Body:
{
"customer": {
"email": "cliente@ejemplo.com",
"name": "Nombre Apellido",
"phone": "+56912345678"
},
"shipping": {
"address": "Av. Las Condes 1234, Santiago",
"zoneId": "zone-id-string"
},
"items": [
{
"productId": "string",
"quantity": 2,
"variantId": "string (opcional)",
"slotId": "string (para experiencias con slot)",
"scheduledDate": "2026-05-01T10:00:00Z (para servicios)",
"scheduledEndDate": "2026-05-01T11:00:00Z",
"notes": "string",
"specialRequests": "string"
}
],
"couponCode": "DESCUENTO20",
"paymentMethod": "MERCADOPAGO"
}
Respuesta 201:
{
"success": true,
"order": {
"id": "string",
"orderNumber": "ORD-2026-0042",
"total": 35974,
"paymentUrl": "https://..."
}
}
GET/api/storefront/checkout/order/:orderNumber#
Estado de una orden.
Respuesta:
{
"order": {
"id": "string",
"orderNumber": "ORD-2026-0042",
"customerName": "string",
"customerEmail": "string",
"total": 35974,
"status": "PENDING | PAID | PROCESSING | SHIPPED | DELIVERED | CANCELLED",
"items": [
{
"id": "string",
"quantity": 2,
"unitPrice": 19990,
"productSnapshot": {
"name": "string",
"price": 19990,
"sku": "string",
"images": ["https://..."]
},
"product": {
"type": "PHYSICAL_PRODUCT",
"files": []
}
}
]
}
}
GET/api/storefront/checkout/shipping/calculate#
Calcula opciones de envío para una ubicación.
Query params:
| Param | Tipo |
|---|---|
commune | string |
region | string |
13. Envíos#
GET/api/storefront/shipping/calculate#
Query params:
| Param | Tipo | Descripción |
|---|---|---|
communeId | string | ID de comuna (ej: RM-01) |
communeName | string | Nombre de comuna |
cartWeight | number | Peso total en kg |
cartTotal | number | Subtotal en CLP |
Respuesta:
{
"success": true,
"shippingMode": "simple | advanced",
"zones": [
{
"id": "string",
"name": "string",
"price": 3990,
"shippingCost": 3990,
"isFree": false,
"freeAbove": 50000,
"deliveryDays": "3-5 días hábiles",
"regions": ["Región Metropolitana"],
"communes": []
}
],
"enviame": [
{
"id": "enviame-1-ECO",
"name": "Chilexpress — Económico",
"price": 4290,
"shippingCost": 4290,
"isFree": false,
"freeAbove": null,
"deliveryDays": "5 días",
"carrier": "Chilexpress",
"carrierId": 1,
"serviceCode": "ECO",
"source": "enviame"
}
],
"pickup": {
"id": "pickup",
"name": "Retiro en tienda",
"shippingCost": 0,
"isFree": true,
"freeAbove": null,
"deliveryDays": null,
"instructions": "Retirar en Av. Ejemplo 123"
}
}
GET/api/storefront/shipping/zones#
Zonas de envío configuradas.
14. Leads#
POST/api/storefront/leads#
Body:
{
"name": "string",
"email": "string",
"phone": "string (opcional)",
"message": "string"
}
Respuesta 201:
{
"success": true,
"message": "Thank you for your message. We will get back to you soon!",
"leadId": "string"
}
15. Formulario de contacto#
POST/api/storefront/contact#
Body:
{
"name": "string",
"email": "string",
"phone": "string (opcional)",
"company": "string (opcional)",
"message": "string (mín 10 caracteres)"
}
Respuesta 201:
{
"success": true,
"message": "Your message has been sent successfully. We will get back to you soon!"
}
16. Newsletter#
POST/api/storefront/newsletter/subscribe#
Body:
{
"email": "string",
"name": "string (opcional)",
"preferences": {},
"source": "string (opcional)"
}
GET/api/storefront/newsletter/verify/:token#
Verifica el email del suscriptor.
GET/api/storefront/newsletter/unsubscribe/:token#
Cancela la suscripción.
PUT/api/storefront/newsletter/preferences#
Actualiza preferencias del suscriptor.
17. Autenticación de cliente (Customer)#
Los clientes (compradores) tienen su propio sistema de auth separado del dashboard.
POST/api/storefront/customer-auth/register#
Body:
{
"email": "string",
"password": "string (mín 8 caracteres)",
"name": "string",
"phone": "string (opcional)"
}
Respuesta 201:
{
"success": true,
"token": "jwt",
"user": { "id": "string", "email": "string", "name": "string" }
}
POST/api/storefront/customer-auth/login#
Body: { "email": "string", "password": "string" }
POST/api/storefront/customer-auth/verify-email#
Body: { "token": "string" }
POST/api/storefront/customer-auth/request-password-reset#
Body: { "email": "string" }
POST/api/storefront/customer-auth/reset-password#
Body: { "token": "string", "newPassword": "string (mín 8 caracteres)" }
18. Cuenta del cliente Requiere auth#
Todos los endpoints de esta sección requieren Authorization: Bearer {customer_jwt}.
GET/api/storefront/customer-account/profile#
Respuesta:
{
"success": true,
"user": {
"id": "string",
"email": "string",
"name": "string",
"phone": "string | null",
"rut": "string | null",
"birthday": "ISO date | null",
"nationality": "string | null",
"emailVerified": true,
"createdAt": "ISO date"
}
}
PUT/api/storefront/customer-account/profile#
Body (todos opcionales): name, phone, rut, birthday, nationality
POST/api/storefront/customer-account/change-password#
Body: { "currentPassword": "string", "newPassword": "string" }
GET/api/storefront/customer-account/addresses#
Respuesta:
{
"addresses": [
{
"id": "string",
"street": "string",
"city": "string",
"state": "string",
"postalCode": "string",
"country": "string",
"isDefault": true,
"name": "string | null",
"phone": "string | null",
"createdAt": "ISO date"
}
]
}
POST/api/storefront/customer-account/addresses#
Body: street, city, state, postalCode, country (requeridos) + isDefault, name, phone (opcionales).
PUT/api/storefront/customer-account/addresses/:addressId#
DELETE/api/storefront/customer-account/addresses/:addressId#
GET/api/storefront/customer-account/orders#
Respuesta:
{
"orders": [
{
"id": "string",
"orderNumber": "ORD-2026-0042",
"total": 35974,
"status": "DELIVERED",
"createdAt": "ISO date",
"items": [
{
"id": "string",
"quantity": 2,
"unitPrice": 19990,
"product": { "id": "string", "name": "string", "images": ["https://..."] }
}
]
}
]
}
GET/api/storefront/customer-account/orders/:orderId#
19. Lista de deseos Requiere auth#
GET/api/storefront/wishlist#
Respuesta: { "success": true, "items": [...], "count": 3 }
POST/api/storefront/wishlist#
Body: { "productId": "string" }
DELETE/api/storefront/wishlist/:productId#
DELETE/api/storefront/wishlist — Vaciar la lista#
GET/api/storefront/wishlist/check/:productId#
Respuesta: { "inWishlist": true }
20. Carrito abandonado#
POST/api/storefront/cart/abandon#
Registra un carrito abandonado para recuperación.
Body:
{
"email": "string",
"customerName": "string (opcional)",
"items": [{ "productId": "string", "quantity": 2 }],
"subtotal": 39980,
"discount": 0,
"total": 39980,
"couponCode": "string (opcional)"
}
GET/api/storefront/cart/recover/:token#
Recupera un carrito abandonado por token (enviado por email).
Respuesta:
{
"success": true,
"data": {
"id": "string",
"email": "string",
"customerName": "string | null",
"items": [],
"subtotal": 39980,
"discount": 0,
"total": 39980,
"couponCode": "string | null",
"recoveredAt": null,
"createdAt": "ISO date"
}
}
410 Gonesi el carrito ya fue recuperado anteriormente.
Tipos de producto#
| Tipo | Descripción | Tiene stock | Tiene booking |
|---|---|---|---|
PHYSICAL_PRODUCT | Producto físico | ✓ | — |
DIGITAL_PRODUCT | Archivo descargable | — | — |
SERVICE | Servicio agendable | — | ✓ |
EXPERIENCE | Experiencia con slots | — | ✓ |
21. Reseñas#
Los endpoints de escritura requieren Authorization: Bearer {customer_jwt}.
GET/api/storefront/reviews/product/:productId#
Query params:
| Param | Tipo | Descripción |
|---|---|---|
page | number | Default: 1 |
limit | number | Default: 10 |
sortBy | string | recent (default), helpful, rating_high, rating_low |
Respuesta:
{
"success": true,
"reviews": [
{
"id": "string",
"rating": 5,
"title": "string | null",
"comment": "string | null",
"createdAt": "ISO date",
"customer": { "name": "string" }
}
],
"pagination": { "page": 1, "limit": 10, "total": 24, "totalPages": 3 }
}
POST/api/storefront/reviews Requiere auth#
Body:
{ "productId": "string", "rating": 5, "title": "string (opcional)", "comment": "string (opcional)" }
GET/api/storefront/reviews/my-review/:productId Requiere auth#
Reseña propia del cliente para un producto.
PUT/api/storefront/reviews/:reviewId Requiere auth#
Body (todos opcionales): rating, title, comment
DELETE/api/storefront/reviews/:reviewId Requiere auth#
POST/api/storefront/reviews/:reviewId/helpful#
Marca una reseña como útil (sin auth).
GET/api/storefront/reviews/my-reviews Requiere auth#
Lista todas las reseñas del cliente autenticado.
22. Servicios#
GET/api/storefront/services#
Query params:
| Param | Tipo | Descripción |
|---|---|---|
page | number | Default: 1 |
limit | number | Default: 20 |
categoryId | string | |
deliveryMethod | string | |
requiresScheduling | true|false | |
search | string |
Respuesta:
{
"success": true,
"services": [
{
"id": "string",
"name": "string",
"slug": "string",
"description": "string",
"price": 15000,
"images": ["https://..."],
"categoryId": "string",
"createdAt": "ISO date",
"imageUrl": "string | null"
}
],
"pagination": { "page": 1, "limit": 20, "total": 8, "totalPages": 1 }
}
GET/api/storefront/services/:slug#
Incluye availableSlots igual que experiencias.
GET/api/storefront/services/:id/slots#
Query params:
| Param | Tipo | Descripción |
|---|---|---|
startDate | ISO date | Default: hoy |
endDate | ISO date | Default: +30 días |
23. Bookings#
POST/api/storefront/bookings#
Crea una reserva para un servicio o experiencia.
Body:
{
"productId": "string",
"slotId": "string (opcional)",
"customerName": "string",
"customerEmail": "string",
"customerPhone": "string",
"participants": 2,
"scheduledDate": "ISO date (opcional)",
"scheduledEndDate": "ISO date (opcional)",
"notes": "string (opcional)",
"specialRequests": "string (opcional)"
}
Respuesta 201:
{
"success": true,
"booking": {
"id": "string",
"product": { "id": "string", "name": "string", "slug": "string", "price": 15000 },
"slot": { "id": "string", "startDateTime": "ISO date", "endDateTime": "ISO date", "price": 15000 },
"customerName": "string",
"customerEmail": "string",
"participants": 2,
"status": "PENDING",
"scheduledDate": "ISO date | null",
"createdAt": "ISO date"
},
"message": "string"
}
GET/api/storefront/bookings/:id#
Consultar estado de una reserva.
Query params: email (requerido, para verificar identidad)
Respuesta:
{
"success": true,
"booking": {
"id": "string",
"product": { "id": "string", "name": "string", "slug": "string", "price": 15000, "images": [] },
"slot": { "id": "string", "startDateTime": "ISO date", "endDateTime": "ISO date", "capacity": 10 },
"customerName": "string",
"customerEmail": "string",
"customerPhone": "string",
"participants": 2,
"status": "PENDING | CONFIRMED | CANCELLED | COMPLETED | NO_SHOW",
"scheduledDate": "ISO date | null",
"scheduledEndDate": "ISO date | null",
"notes": "string | null",
"specialRequests": "string | null",
"confirmedAt": "ISO date | null",
"cancelledAt": "ISO date | null",
"cancellationReason": "string | null",
"createdAt": "ISO date"
}
}
POST/api/storefront/bookings/:id/cancel#
Body:
{ "email": "string", "reason": "string" }
24. Rifas#
GET/api/storefront/raffles#
Query params:
| Param | Tipo | Descripción |
|---|---|---|
page | number | Default: 1 |
limit | number | Default: 20 |
status | string | Estado de la rifa |
featured | true|false | |
categoryId | string | |
categorySlug | string | |
tagSlug | string | |
search | string | |
hasAvailableTickets | true|false | Solo rifas con tickets disponibles |
GET/api/storefront/raffles/:slug#
Respuesta: incluye availableTickets (número de tickets aún disponibles).
GET/api/storefront/raffles/:slug/available-numbers#
Números de tickets aún disponibles para compra.
POST/api/storefront/raffles/:slug/purchase#
Body:
{
"email": "string",
"phone": "string",
"quantity": 2,
"ticketNumbers": [1, 2]
}
Respuesta:
{
"success": true,
"tickets": [],
"totalPrice": 10000,
"expiresAt": "ISO date",
"message": "string"
}
GET/api/storefront/raffles/:slug/stats#
Respuesta:
{
"ticketsSold": 150,
"ticketsRemaining": 350,
"totalTickets": 500,
"progress": 30,
"participantsCount": 80
}
POST/api/storefront/raffles/:slug/verify-draw#
Verifica la transparencia de un sorteo (hash pública).
Body: { "drawHash": "string", "drawSeed": "string" }
25. Tags#
GET/api/storefront/tags#
Respuesta:
{
"success": true,
"tags": [
{
"id": "string",
"name": "string",
"slug": "string",
"color": "#hex",
"icon": "string | null",
"description": "string | null",
"order": 0,
"_count": { "productTags": 12 }
}
]
}
GET/api/storefront/tags/:slug#
26. Regiones y comunas (Chile)#
Datos geográficos estáticos de Chile (16 regiones).
GET/api/storefront/regions#
Respuesta:
{
"success": true,
"regions": [
{ "id": "string", "code": "RM", "name": "Región Metropolitana", "communeCount": 52 }
]
}
GET/api/storefront/regions/:id/communes#
Respuesta:
{
"success": true,
"communes": [
{ "id": "string", "code": "RM-01", "name": "Santiago" }
]
}
27. Seguimiento de órdenes#
GET/api/storefront/orders/track/:orderNumber#
Query params: email (requerido)
Respuesta:
{
"success": true,
"order": {
"orderNumber": "ORD-2026-0042",
"status": "SHIPPED",
"customerName": "string",
"total": 35974,
"items": [],
"tracking": { "carrier": "string", "trackingNumber": "string", "trackingUrl": "string | null" }
}
}
Errores: ORDER_NOT_FOUND (404), TRACKING_ERROR (500)
GET/api/storefront/orders/track/:orderNumber/timeline#
Query params: email (requerido)
Devuelve la línea de tiempo de eventos de la orden.
POST/api/storefront/orders/track/notify#
Suscribe al cliente para recibir notificaciones de estado de la orden.
Body: { "orderNumber": "string", "email": "string" }
28. Promociones#
GET/api/storefront/promotions#
Promociones activas del tenant.
Respuesta:
{
"success": true,
"promotions": [
{
"id": "string",
"name": "string",
"description": "string | null",
"type": "PERCENTAGE | FIXED_AMOUNT | FREE_SHIPPING | QUANTITY_DISCOUNT | BUY_X_GET_Y",
"value": 20,
"scope": "STORE_WIDE | CATEGORY | PRODUCT",
"minPurchase": 30000,
"expiresAt": "ISO date | null"
}
]
}
GET/api/storefront/promotions/banners#
Hasta 3 promociones activas para mostrar en banners/ribbon.
29. Eventos de analytics#
POST/api/storefront/events#
Registra un evento de comportamiento del usuario (page views, conversiones, etc.).
Body:
{
"type": "page_view | product_view | add_to_cart | remove_from_cart | begin_checkout | add_payment_info | purchase | booking_created | form_view | form_start | lead_submit | contact_submit | newsletter_subscribe | phone_click | whatsapp_click | cta_click | search | category_view | blog_view",
"eventId": "string (opcional)",
"sessionId": "string (opcional)",
"pageUrl": "string (opcional)",
"utmSource": "string (opcional)",
"utmMedium": "string (opcional)",
"utmCampaign": "string (opcional)",
"utmContent": "string (opcional)",
"utmTerm": "string (opcional)",
"fbclid": "string (opcional)",
"gclid": "string (opcional)",
"ga4ClientId": "string (opcional)",
"email": "string (opcional)",
"payload": {}
}
Respuesta: { "success": true }
30. Academy (módulo de cursos) Requiere auth#
Disponible solo en tenants con el módulo
coursesEnabledactivo.
Los endpoints marcados con Requiere auth requieren Authorization: Bearer {student_jwt}.
El JWT de alumno se obtiene desde los endpoints de auth de academy (distinto al JWT de customer).
Auth de alumnos#
POST/api/academy/auth/register
Body: { "name": "string", "email": "string", "password": "string (mín 8 caracteres)", "phone": "string (opcional)", "referralCode": "string (opcional)" }
Respuesta 201:
{ "success": true, "token": "student_jwt", "student": { "id": "string", "name": "string", "email": "string" } }
POST/api/academy/auth/login
Body: { "email": "string", "password": "string" }
Respuesta: igual a register.
PATCH/api/academy/auth/profile Requiere auth
Body (todos opcionales): name, phone, avatar
POST/api/academy/auth/avatar Requiere auth
Sube una imagen de perfil (multipart/form-data, campo file, máx 2 MB, formatos JPG/PNG/WebP).
Respuesta: { "url": "https://..." }
Catálogo público#
GET/api/academy/courses
Query params:
| Param | Tipo | Descripción |
|---|---|---|
page | number | Default: 1 |
limit | number | Default: 20 |
Respuesta:
{
"courses": [
{
"id": "string",
"title": "string",
"slug": "string",
"description": "string | null",
"price": 49990,
"coverImage": "string | null",
"published": true,
"createdAt": "ISO date"
}
],
"pagination": { "page": 1, "limit": 20, "total": 5, "totalPages": 1 }
}
GET/api/academy/courses/:slug
Detalle completo del curso (secciones, lecciones, instructor, precio).
Inscripción y progreso Requiere auth#
POST/api/academy/courses/:courseId/enroll Requiere auth
Body:
{
"backUrls": {
"success": "https://...",
"failure": "https://...",
"pending": "https://..."
},
"referralCode": "string (opcional)",
"useCredits": true
}
Respuesta (curso gratuito o crédito cubre total):
{ "enrolled": true, "enrollment": { "id": "string", "paymentStatus": "FREE" }, "discountApplied": 0 }
Respuesta (requiere pago):
{ "enrolled": false, "enrollment": { "id": "string", "paymentStatus": "PENDING" }, "checkoutUrl": "https://...", "discountApplied": 4999 }
GET/api/academy/enrollments/:enrollmentId Requiere auth
Estado y detalle de una inscripción.
GET/api/academy/courses/:courseId/progress Requiere auth
Progreso del alumno en el curso (lecciones completadas, porcentaje).
Lecciones Requiere auth#
GET/api/academy/lessons/:lessonId Requiere auth
Contenido de una lección (requiere estar inscrito en el curso padre).
POST/api/academy/lessons/:lessonId/complete Requiere auth
Marca una lección como completada.
Quizzes Requiere auth#
POST/api/academy/quizzes/:quizId/attempt Requiere auth
Body:
{
"answers": [
{ "questionId": "string", "selectedOptionId": "string" }
]
}
Respuesta:
{
"passed": true,
"score": 80,
"correctAnswers": 4,
"totalQuestions": 5,
"attemptNumber": 1
}
Foro Requiere auth#
GET/api/academy/courses/:courseId/forum Requiere auth
Query params: lessonId (opcional, filtra threads de esa lección)
POST/api/academy/courses/:courseId/forum/threads Requiere auth
Body: { "title": "string", "content": "string", "lessonId": "string (opcional)" }
GET/api/academy/forum/threads/:threadId Requiere auth
Detalle de un thread con sus respuestas.
POST/api/academy/forum/threads/:threadId/reply Requiere auth
Body: { "content": "string", "imageUrls": ["https://..."] }
PATCH/api/academy/forum/posts/:postId Requiere auth
Body: { "content": "string" }
DELETE/api/academy/forum/posts/:postId Requiere auth
POST/api/academy/forum/posts/:postId/react Requiere auth
Body: { "type": "LIKE | DISLIKE" }
POST/api/academy/forum/upload-image Requiere auth
Sube una imagen para el foro (multipart, campo file, máx 5 MB, solo imágenes).
Respuesta: { "url": "https://..." }
Referidos#
GET/api/academy/referral/code Requiere auth
Obtiene (o crea) el código de referido del alumno y sus estadísticas.
Respuesta:
{
"code": "JUAN-ABC1",
"shareUrl": "https://tudominio.com/cursos?ref=JUAN-ABC1",
"stats": {
"totalReferrals": 3,
"pendingCredits": 4999,
"availableCredits": 9998
}
}
GET/api/academy/referral/validate?code=XXXX
Valida un código de referido (público, sin auth).
Query params: code (requerido), courseId (opcional, para calcular monto exacto de descuento)
Respuesta:
{ "valid": true, "discount": 10, "discountAmount": 4999 }
GET/api/academy/referral/history Requiere auth
Historial de referidos del alumno.
Biblioteca de recursos#
GET/api/academy/resources Requiere auth
Recursos globales del tenant accesibles para el alumno: recursos públicos globales + recursos concedidos personalmente.
Respuesta:
{
"success": true,
"resources": [
{
"id": "string",
"title": "string",
"description": "string | null",
"fileUrl": "https://...",
"fileName": "string",
"fileType": "PDF | VIDEO | IMAGE | AUDIO | ZIP | FILE",
"fileSize": 204800,
"createdAt": "ISO date",
"granted": false
}
]
}
granted: trueindica que fue concedido personalmente por el admin;granted: falsees público.
GET/api/academy/courses/:courseId/resources Requiere auth
Recursos del curso específico (públicos + concedidos personalmente). Requiere inscripción activa o gratuita en el curso.
Webhooks (solo plan Max)#
El tenant puede configurar webhooks para recibir eventos en su URL. Eventos disponibles:
| Evento | Descripción |
|---|---|
order.created | Nueva orden creada |
customer.created | Nuevo cliente registrado |
abandoned_cart.created | Carrito abandonado registrado |
lead.created | Nuevo lead desde formulario |
contact.created | Nuevo mensaje de contacto |
Última actualización: 2026-04-17