Ir al artículo
Aniq-UI

Food StudioReferencia de la API

Referencia de la API

Cada ruta que sirve la API, quién puede llamarla, y cómo funcionan el inicio de sesión, los permisos, los errores, las listas y los límites.

Para el paquete Full Stack

URL base y formato de respuesta

Todas las rutas se sirven bajo el prefijo /api. En local, la URL base es http://localhost:8000/api. En un servidor es la dirección de tu API seguida de /api, el mismo valor que leen los dos frontends de NEXT_PUBLIC_API_BASE_URL (Variables de entorno).

La API sirve a dos públicos que nunca comparten un token: los clientes, que usan las rutas del sitio web, y el personal, que usa las del panel. Los cuerpos de las peticiones son JSON, salvo las subidas de archivos. Cada respuesta llega en el mismo envoltorio:

Envoltorio
{
  "success": true,
  "data": { },
  "message": ""
}

data contiene el resultado. message es una frase breve que rellenan algunas escrituras, en el idioma de la petición, y si no está vacío. El dinero va en dólares decimales en JSON, por ejemplo 14.99, y cada total lo calcula la API: no se confía en nada que un cliente envíe sobre dinero.

La comprobación de estado no necesita token:

Terminal
curl http://localhost:8000/api/health
Respuesta
{"success":true,"data":{"status":"ok","database":"up"},"message":""}

Cuando no se puede leer la base de datos, sigue respondiendo 200, con "status":"degraded" y "database":"down". La comprobación de estado de la imagen de Docker lee ese campo.

Errores

Un fallo mantiene el envoltorio, con success: false y el estado HTTP:

Error
{
  "success": false,
  "data": null,
  "message": "errors.kitchen_closed",
  "errors": { "email": ["…"] },
  "code": "…"
}
  • Los errores que ve un cliente son claves como errors.kitchen_closed, errors.outside_area o errors.rate_limited, que el sitio web traduce por sí mismo. Los demás mensajes son frases en el idioma de la petición.
  • errors aparece en un fallo de validación, con los problemas por campo.
  • code lleva un motivo legible por máquina cuando existe, por ejemplo changes con una lista changes cuando un precio cambió antes de hacer un pedido.
  • Una ruta protegida sin token responde 401; un token sin el permiso responde 403.

Listas y paginación

Las rutas de lista aceptan page y limit (también se acepta page_count en lugar de limit). limit tiene un máximo de 100. Salvo que quien llama ordene, las filas llegan de la actualizada más recientemente a la más antigua, con el id como desempate, así que la paginación es estable.

Menú y pedidos
{ "items": [ ], "total": 64, "page": 1, "limit": 12, "totalPages": 6 }

Las listas de platos y de pedidos ponen las filas bajo items. Las listas de categorías, reseñas, clientes, equipo, roles y ajustes las ponen bajo data, con los mismos campos de paginación. Las listas que se leen en una secuencia, como las secciones de la página de inicio y la cola de las cocinas, mantienen esa secuencia.

Idioma

Envía Accept-Language: ar para recibir mensajes en árabe; cualquier otro valor responde en inglés. Los registros del menú llevan los dos idiomas como { "en": "…", "ar": "…" } diga lo que diga la cabecera, y el cliente elige uno.

Inicio de sesión

  1. Inicia sesión como personal

    Terminal
    curl -X POST http://localhost:8000/api/auth/login \
      -H "Content-Type: application/json" \
      -d '{"email":"owner@foodstudio.example","password":"FoodDemo2026!"}'

    data.access_token es el token del personal, con token_type Bearer, expires_in (7d por defecto, JWT_EXPIRATION) y el miembro con sus roles. GET /api/auth/me devuelve el miembro con sesión iniciada con sus permisos.

  2. Llama a una ruta protegida

    Terminal
    curl http://localhost:8000/api/orders -H "Authorization: Bearer YOUR_TOKEN"
  3. Inicia sesión como cliente

    POST /api/auth/customer/login con el mismo cuerpo responde { token, user }; POST /api/auth/customer/register acepta first_name, last_name, email, password (8 caracteres o más) y, opcionalmente, phone, y responde lo mismo. El cliente de demostración es sam@foodstudio.example con FoodDemo2026!.

  • Un token de cliente se rechaza en todas las rutas del personal, y un token del personal en todas las rutas de clientes.
  • Un correo desconocido y una contraseña incorrecta responden ambos 401 con el mismo mensaje.
  • Diez inicios de sesión fallidos desde una misma dirección en 15 minutos, por formulario, responden 429 hasta que el fallo más antiguo tiene 15 minutos (RATE_LIMIT_LOGIN). Los inicios de sesión correctos no cuentan.
  • No hay ruta para cerrar sesión: un cliente cierra sesión olvidando su token.
MétodoRutaQuién puede llamarlaQué hace
POST/api/auth/loginCualquieraInicio de sesión del personal
GET/api/auth/meCualquier miembro del personal con sesión iniciadaEl miembro con sesión iniciada, sus roles y sus permisos
POST/api/auth/customer/registerCualquieraCrea una cuenta de cliente e inicia sesión. Un client_token repetido devuelve la cuenta del primer intento
POST/api/auth/customer/loginCualquieraInicio de sesión de clientes
GET/api/auth/customer/meClienteEl perfil, con reward_points
PATCH/api/auth/customer/meClienteEdita first_name, last_name, email, phone
PATCH/api/auth/customer/me/passwordClienteCambia la contraseña: current_password, new_password
POST/api/auth/customer/forgot-passwordCualquieraEnvía por correo un enlace de restablecimiento. Siempre responde { sent: true }, para cualquier dirección
POST/api/auth/customer/reset-passwordCualquieraCompleta un restablecimiento: token, password. Un token funciona una vez, durante una hora

Permisos

Las rutas del personal comprueban un permiso, con el nombre <module>.<action>. Un miembro tiene todos los permisos de todos sus roles.

MóduloPermisos
Equipoadmins.view, admins.create, admins.edit, admins.delete, admins.assign_roles
Rolesroles.view, roles.create, roles.edit, roles.delete, roles.assign_permissions
Ajustes, cocinas y códigos promocionalessettings.view, settings.edit
Clientesusers.view, users.create, users.update, users.delete, users.restore, users.verify
Categoríascategories.view, categories.create, categories.edit, categories.delete, categories.restore
Menú, ofertas y página de inicioproducts.view, products.create, products.edit, products.delete, products.restore
Pedidos y el resumenorders.view, orders.edit
IAai_studio.use, ai_chat.use, ai_chat.view_models
Rol de los datos inicialesConcede
PropietarioTodos los permisos
ManagerTodos los permisos excepto admins.* y roles.*
Cocinaorders.view y orders.edit, limitados a los pedidos de su propia cocina, sin precios ni correo del cliente, y solo los pasos de confirmado a en preparación y de en preparación a listo
MétodoRutaQuién puede llamarlaQué hace
GET/api/productsCualquiera; el personal también ve las filas ocultasEl menú publicado. q, category (slug), dietary (separados por comas), available, sort (popularity, price_asc, price_desc, name), page, limit (12 por defecto). scope=admin con products.view lista todos los platos, borradores incluidos
GET/api/products/featuredCualquieraLos platos destacados
GET/api/products/slug/:slugCualquiera; el personal también ve las filas ocultasUn plato por su slug, con los platos related
GET/api/products/:idCualquiera; el personal también ve las filas ocultasUn plato por su id
GET/api/products/:id/relatedCualquieraPlatos de la misma categoría, y luego los más vendidos
GET/api/categoriesCualquiera; el personal también ve las filas ocultasLas categorías, en su orden en el menú
GET/api/categories/rootsCualquieraLas categorías de primer nivel
GET/api/categories/slug/:slugCualquiera; el personal también ve las filas ocultasUna categoría por su slug
GET/api/categories/:idCualquiera; el personal también ve las filas ocultasUna categoría por id
GET/api/offersCualquiera; el personal también ve las filas ocultasLos combos, con sus opciones, suplementos y ahorros
GET/api/offers/:codeCualquiera; el personal también ve las filas ocultasUn combo, por ejemplo classic-combo
GET/api/homepage-sectionsCualquiera; el personal también ve las filas ocultasLas secciones de la página de inicio, en el orden de la página
GET/api/homepage-sections/:key/productsCualquieraLos platos que muestra una sección, en orden
GET/api/reviews/product/:productIdCualquieraLas reseñas de un plato
GET/api/reviews/product/:productId/summaryCualquieraLa media, el total y el recuento por estrellas

Un plato lleva name, description e ingredients en los dos idiomas, price, su category, images, option_groups con sus choices y el price_delta de cada elección, allergens, dietary_tags, preparation_minutes, y los interruptores is_active (publicado), is_available (se puede pedir ahora), is_featured e is_best_seller.

Cocinas y la comprobación del código postal

MétodoRutaQuién puede llamarlaQué hace
GET/api/kitchensCualquiera; el personal también ve las filas ocultasLas cocinas, cada una con su horario, su zona horaria, su tiempo de preparación, sus códigos postales de entrega y si está abierta ahora
GET/api/kitchens/:codeCualquiera; el personal también ve las filas ocultasUna cocina, por ejemplo central
POST/api/kitchens/checkCualquieraQué cocina puede dar servicio a un código postal
POST /api/kitchens/check
{ "postcode": "10001", "mode": "delivery", "kitchen_code": "central" }

Responde { result, kitchen, alternatives }, donde result es match, outside_area o closed. La recogida no está limitada por el código postal. Si una cocina está abierta depende del ajuste del reloj de servicio.

Precios, códigos promocionales y el carrito

MétodoRutaQuién puede llamarlaQué hace
POST/api/checkout/quoteCualquiera; si se envía un token de cliente, se leeCalcula el precio de un carrito para una cocina sin escribir nada
POST/api/promo/validateCualquieraLo que descontaría un código de un subtotal: { code, subtotal }
GET/api/cartClienteEl carrito en el servidor del cliente con sesión iniciada, con su presupuesto
POST/api/cart/itemsClienteAñade una selección
PATCH/api/cart/items/:idClienteCambia la cantidad, las opciones o la nota de una línea
DELETE/api/cart/items/:idClienteQuita una línea
DELETE/api/cartClienteVacía el carrito
PUT/api/cart/metaClienteCambia la cocina y la entrega o recogida
POST/api/cart/mergeClienteIncorpora un carrito de invitado al iniciar sesión, sin sustituir nunca una línea
POST /api/checkout/quote
{
  "lines": [
    { "product_id": 9, "quantity": 1, "options": [{ "group": "size", "choice": "double" }], "instructions": "no onions" },
    { "offer_id": 1, "quantity": 1, "offer_choices": { "main": 9, "side": 5, "drink": 3 } }
  ],
  "kitchen_code": "central",
  "fulfillment": "delivery",
  "address": { "street": "12 Main St", "city": "Demo City", "postcode": "10001" },
  "promo_code": "TASTE10"
}
  • Una línea indica un product_id o un offer_id, con una quantity de 1 a 10 e instructions de 200 caracteres como máximo.
  • El presupuesto indica el subtotal, los descuentos, la tarifa, el total, los puntos que ganaría el pedido, si la entrega puede hacerse (address_incomplete, outside_area, closed, below_minimum) y una lista changes para cualquier línea cuyo precio cambió o que no se puede pedir.
  • Un código promocional descuenta su porcentaje del subtotal del menú, nunca de la tarifa de entrega. redeem_points: true aplica un canje para un cliente con sesión iniciada que tenga puntos suficientes.

Hacer un pedido y seguirlo

MétodoRutaQuién puede llamarlaQué hace
POST/api/ordersCualquiera; si se envía un token de cliente, se leeHace un pedido. Necesita una cabecera Idempotency-Key
GET/api/orders/myClienteLos pedidos del cliente, del más reciente al más antiguo
GET/api/orders/number/:orderNumberClienteUno de los pedidos del propio cliente, por ejemplo FS-1042
GET/api/orders/trackCualquieraSeguimiento para invitados: ?number=FS-1042&email=…
GET/api/orders/track/statusCualquieraEn qué punto está un pedido, para quien tiene un token de seguimiento: ?token=…
  • POST /api/orders acepta las lines del presupuesto, kitchen_code, fulfillment y address, más phone, payment_method (stripe, paypal o demo, según lo que liste GET /api/payments/methods), terms_accepted: true y, para un invitado, name y email. Opcionales: promo_code, redeem_points, delivery_instructions, locale, accept_changes, y return_url_ok y return_url_cancel, que deben estar en una dirección de CORS_ORIGIN.
  • Responde 201 con { order, payment, tracking }. payment.kind es redirect, con la página del proveedor en payment.url, o none para el pago de demostración, que luego paga POST /api/payments/checkout-session. tracking es un token firmado, válido durante tres horas, para GET /api/orders/track/status.
  • La misma Idempotency-Key de la misma persona devuelve el pedido guardado en lugar de crear un segundo.
  • Un precio que cambió, o un plato que dejó de estar disponible, responde 422 con code: "changes" hasta que el cliente envía la clave del cambio en accept_changes.
  • El seguimiento para invitados responde el mismo 404 para un número desconocido, un correo incorrecto y parámetros que faltan.

El estado de un pedido pasa por pending, confirmed, preparing, ready, y luego out_for_delivery y delivered para la entrega, o directamente a delivered para la recogida. Puede pasar a cancelled con un motivo antes de salir de la cocina, y solo pasa a refunded cuando el proveedor de pago informa de un reembolso.

Pagos

MétodoRutaQuién puede llamarlaQué hace
GET/api/payments/methodsCualquieraLo que puede ofrecer el pago: { methods, hosted, modes }, cada método test o live
POST/api/payments/checkout-sessionCualquiera; si se envía un token de cliente, se leePaga, o reabre el pago de, un pedido pendiente sin pagar: { order_number, email? }
GET/api/payments/return/stripeEl navegador, al volver de Stripe (dirección firmada)Confirma el pago con Stripe y luego redirige al sitio web con ?order=…&payment=paid|pending|cancelled|failed
GET/api/payments/return/paypalEl navegador, al volver de PayPal (dirección firmada)Captura el pago aprobado y luego redirige de la misma forma
POST/api/payments/webhooks/:providerStripe, PayPal o quien llama al pago de demostraciónstripe, paypal o demo. Una llamada sin firmar o alterada responde 401

Direcciones, platos guardados, recompensas, reseñas y contacto

MétodoRutaQuién puede llamarlaQué hace
GET/api/addressesClienteLas direcciones de entrega guardadas
GET/api/addresses/:idClienteUna dirección
POST/api/addressesClienteGuarda una dirección
PATCH/api/addresses/:idClienteEdita una dirección
PATCH/api/addresses/:id/defaultClienteLa convierte en predeterminada
DELETE/api/addresses/:idClienteElimina una dirección
GET/api/wishlistClienteLos platos guardados
PUT/api/wishlist/:productIdClienteGuarda un plato
DELETE/api/wishlist/:productIdClienteQuita un plato
DELETE/api/wishlistClienteQuita todos los platos guardados
POST/api/wishlist/mergeClienteAñade los platos guardados de un invitado al iniciar sesión
GET/api/rewards/meClienteEl saldo de puntos, el coste y el valor de un canje, y el historial
POST/api/reviewsClienteEscribe una reseña de un plato
PATCH/api/reviews/:idClienteEdita la reseña propia
DELETE/api/reviews/:idClienteElimina la reseña propia
POST/api/contactCualquieraEl formulario de contacto: name, email, message, client_token. Llega al personal como notificación

Personal: menú, categorías, combos y página de inicio

MétodoRutaQuién puede llamarlaQué hace
POST/api/productsPersonal con products.createCrea un plato
PATCH/api/products/:idPersonal con products.editEdita un plato. images y option_groups sustituyen todo el conjunto cuando se envían
PATCH/api/products/:id/availabilityPersonal con products.edit{ is_available }: el interruptor que una cocina activa o desactiva durante el servicio
DELETE/api/products/:idPersonal con products.deleteArchiva un plato
GET/api/products/deletedPersonal con products.deleteLos platos archivados
POST/api/products/deleted/:id/restorePersonal con products.restoreRestaura un plato
GET/api/products/statisticPersonal con products.viewRecuentos del menú
GET/api/products/draftsCualquier miembro del personal con sesión iniciadaEl borrador guardado automáticamente del formulario del plato
PUT/api/products/draftsCualquier miembro del personal con sesión iniciadaGuarda el borrador
DELETE/api/products/draftsCualquier miembro del personal con sesión iniciadaDescarta el borrador
POST/api/categoriesPersonal con categories.createCrea una categoría
PATCH/api/categories/:idPersonal con categories.editEdita una categoría
DELETE/api/categories/:idPersonal con categories.deleteArchiva una categoría
GET/api/categories/deletedPersonal con categories.deleteLas categorías archivadas
POST/api/categories/deleted/:id/restorePersonal con categories.restoreRestaura una categoría
GET/api/categories/statisticPersonal con categories.viewRecuentos de categorías
POST/api/offersPersonal con products.createCrea un combo
PATCH/api/offers/:codePersonal con products.editEdita un combo
DELETE/api/offers/:codePersonal con products.deleteElimina un combo
GET/api/homepage-sections/:keyPersonal con products.viewUna sección de la página de inicio
PUT/api/homepage-sections/:keyPersonal con products.editEdita una sección: title, content, position, is_visible, product_ids. Lo que no se envía se queda como estaba

Personal: pedidos y el resumen

MétodoRutaQuién puede llamarlaQué hace
GET/api/ordersPersonal con orders.viewTodos los pedidos que puede ver el miembro: status (separados por comas), fulfillment, date (today, yesterday o un día), q, sort_by, sort_order, paginación
GET/api/orders/:idPersonal con orders.viewUn pedido con su cronología
GET/api/orders/statisticPersonal con orders.viewRecuentos por estado, y los ingresos pagados para las cuentas que ven dinero
PATCH/api/orders/:id/statusPersonal con orders.editMueve un pedido: { status, reason? }. Una cancelación necesita un motivo
GET/api/overviewPersonal con orders.viewLa página principal del panel: ?range=today o yesterday. Se rechaza a las cuentas de cocina
  • Un paso que la secuencia de estados no permite responde 409 errors.transition_not_allowed; uno que esta cuenta no puede dar, 403 errors.transition_forbidden; confirmar un pedido sin pagar, 409 errors.payment_required.
  • Una cuenta de cocina solo ve los pedidos de su propia cocina, sin precios, y cualquier otro pedido responde 404.

Personal: clientes, equipo y roles

MétodoRutaQuién puede llamarlaQué hace
GET/api/usersPersonal con users.viewClientes, con búsqueda y filtros
GET/api/users/statisticPersonal con users.viewRecuentos de clientes
GET/api/users/:usernamePersonal con users.viewUn cliente
POST/api/usersPersonal con users.createCrea un cliente
PATCH/api/users/:usernamePersonal con users.updateEdita un cliente
PATCH/api/users/:username/change-passwordPersonal con users.updateEstablece la contraseña de un cliente
POST/api/users/:username/make-verifiedPersonal con users.verifyMarca el correo como verificado
POST/api/users/:username/make-unverifiedPersonal con users.verifyMarca el correo como no verificado
DELETE/api/users/:usernamePersonal con users.deleteElimina un cliente
GET/api/users/deletedPersonal con users.viewClientes eliminados
GET/api/users/deleted/:usernamePersonal con users.viewUn cliente eliminado
POST/api/users/deleted/:username/restorePersonal con users.restoreRestaura un cliente
GET/api/adminsPersonal con admins.viewEl equipo
GET/api/admins/statisticsPersonal con admins.viewRecuentos del equipo
GET/api/admins/:idPersonal con admins.viewUn miembro, por id o nombre de usuario
POST/api/adminsPersonal con admins.createAñade un miembro
PATCH/api/admins/:idPersonal con admins.editEdita un miembro, incluida su cocina
PATCH/api/admins/:id/rolesPersonal con admins.assign_rolesAsigna los roles de un miembro
DELETE/api/admins/:idPersonal con admins.deleteElimina un miembro
PATCH/api/admins/profilePersonal con admins.editEdita el perfil propio
PATCH/api/admins/profile/passwordCualquier miembro del personal con sesión iniciadaCambia la contraseña propia
GET/api/rolesPersonal con roles.viewLos roles
GET/api/roles/statisticsPersonal con roles.viewRecuentos de roles
GET/api/roles/selectPersonal con roles.viewLos roles, con el formato de un selector
GET/api/roles/permissionsPersonal con roles.viewTodos los permisos
GET/api/roles/:idPersonal con roles.viewUn rol con sus permisos
POST/api/rolesPersonal con roles.createCrea un rol
PUT/api/roles/:idPersonal con roles.editRenombra un rol
POST/api/roles/:id/permissionsPersonal con roles.assign_permissionsAsigna los permisos de un rol
DELETE/api/roles/:idPersonal con roles.deleteElimina un rol

Personal: ajustes, cocinas, códigos promocionales, subidas y notificaciones

MétodoRutaQuién puede llamarlaQué hace
GET/api/settingsPersonal con settings.viewCada ajuste guardado: search, category, paginación
GET/api/settings/:keyPersonal con settings.viewUn ajuste, por ejemplo delivery_fee
PATCH/api/settings/:keyPersonal con settings.editCambia un ajuste
DELETE/api/settings/:keyPersonal con settings.editElimina un ajuste
POST/api/kitchensPersonal con settings.editAñade una cocina
PATCH/api/kitchens/:codePersonal con settings.editEdita una cocina
DELETE/api/kitchens/:codePersonal con settings.editElimina una cocina
GET/api/promoPersonal con settings.viewLos códigos promocionales
POST/api/promoPersonal con settings.editCrea un código: code, percent, excludes_delivery, stackable_with_rewards, is_active
PATCH/api/promo/:idPersonal con settings.editEdita un código
DELETE/api/promo/:idPersonal con settings.editElimina un código. Los pedidos lo conservan como texto
POST/api/helpers/uploadCualquier miembro del personal con sesión iniciadaSube una imagen o un vídeo, multipart/form-data con file, hasta 150 MB
GET/api/notificationsCualquier miembro del personal con sesión iniciadaLas 30 notificaciones más recientes del miembro y el recuento de no leídas
PATCH/api/notifications/read-allCualquier miembro del personal con sesión iniciadaMarca todas las notificaciones como leídas
PATCH/api/notifications/:id/readCualquier miembro del personal con sesión iniciadaMarca una como leída
DELETE/api/notifications/:idCualquier miembro del personal con sesión iniciadaElimina una
  • Los ajustes con los que funciona el restaurante son delivery_fee, pickup_fee, delivery_minimum, rewards_points_per_dollar, rewards_redeem_points, rewards_redeem_value y service_clock (real o demo-fixed), junto a site_name, site_tagline, support_email y support_phone.
  • Una imagen subida se guarda como JPEG en varios tamaños, y la respuesta relaciona cada versión con su dirección. Los archivos van al bucket cuando las variables R2_* están configuradas y, si no, a /media/uploads/… en la API.
  • Cada ruta de notificaciones responde con todo el listado, así que un cliente sustituye lo que tiene por la respuesta.

Límites por dirección

RutaLímiteVariable
POST /api/auth/login, POST /api/auth/customer/login10 inicios de sesión fallidos cada 15 minutos, por formularioRATE_LIMIT_LOGIN
POST /api/orders10 cada 10 minutosRATE_LIMIT_ORDERS
POST /api/payments/checkout-session30 cada 10 minutosRATE_LIMIT_PAYMENT_SESSION
GET /api/orders/track30 cada 10 minutosRATE_LIMIT_TRACKING
POST /api/auth/customer/register10 por horaRATE_LIMIT_REGISTER
POST /api/contact5 por horaRATE_LIMIT_CONTACT
POST /api/auth/customer/forgot-password10 por hora, y 5 mensajes por destinatario al díaRATE_LIMIT_PASSWORD_RESET, MAIL_MAX_PER_ADDRESS_PER_DAY

Una petición que supera un límite responde 429 con errors.rate_limited. Los recuentos viven en la memoria de la API, así que un reinicio los borra. Detrás de un proxy inverso, configura TRUST_PROXY para que cada visitante se cuente por su propia dirección.

El asistente de IA y sus conversaciones

Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.

Las rutas en streaming del asistente, su lista de modelos y las conversaciones guardadas.

Estudio de IA

Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.

Las rutas del estudio: fichas, generaciones, guardado de resultados y eliminación del fondo.

Servidor MCP

Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.

El endpoint MCP para agentes de programación y cómo se autoriza.

Actualizaciones en directo por WebSocket

Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.

Los namespaces de Socket.IO que escucha el panel, sus eventos y cómo se autoriza una conexión.

Rutas del modo demostración

Incluido con tu compra. Inicia sesión para leerlo o ábrelo en tu descarga.

Las rutas que solo existen en una versión de demo pública.

¿Te atascaste en un paso?

Busca una solución antes de empezar de nuevo.

Solución de problemas

Preferencias de Cookies

Utilizamos cookies para mejorar tu experiencia de navegación, analizar el tráfico del sitio y personalizar el contenido. Al hacer clic en "Aceptar Todo", consientes nuestro uso de cookies para análisis y publicidad personalizada.