1. Todo ya funciona por separado…
A estas alturas ya os hacéis una idea de cómo gira el flujo de commerce alrededor de ChatGPT. El merchant tiene un Product Feed, están implementados los endpoints de ACP (/checkout_sessions y compañía), Instant Checkout procesa el pago y el backend recibe webhooks y crea pedidos. Todo esto puede funcionar incluso sin vuestro ChatGPT App: basta con Product Feed + ACP‑backend.
Por separado ya sabéis:
- generar un Product Feed según la especificación de OpenAI;
- diseñar e implementar Agentic Checkout / Delegated Payment;
- crear un ChatGPT App con widget y herramientas MCP para buscar regalos.
Por separado todo se ve fenomenal, pero junto es fácil que se convierta en un «zoológico de servicios». El widget va por su lado, el servidor MCP por el suyo, el ACP‑backend por otro, y la lógica de pedidos y webhooks por un cuarto. En cuanto intentáis depurar una compra real o arreglar un bug extraño, de pronto os dais cuenta de que nadie ve realmente el cuadro completo.
El objetivo de esta lección es sacaros de ese estado y daros una arquitectura coherente y a la vez realizable: cómo se relaciona exactamente el Product Feed con el ACP‑backend, cómo se vinculan ambos con el ChatGPT App y el widget, dónde entra el proveedor de pagos y cómo se envuelve todo esto en componentes comprensibles para el equipo: servicios, BD y API.
Al mismo tiempo subrayaremos constantemente qué es un SPEC estricto y qué es tan solo nuestra elección de arquitectura para GiftGenius.
Insight: ChatGPT es un Google gratuito
ChatGPT trata con los usuarios de forma muy similar a Google: os trae tráfico relevante gratis, porque gana dinero con otra cosa: con los propios usuarios.
Desde el punto de vista del negocio, esto significa algo simple: ChatGPT se convierte en un «canal publicitario» gratuito para vuestros productos, siempre que hayáis conectado Product Feed y el ACP‑backend. El modelo propondrá vuestros artículos si encajan bien con la petición del usuario, y no necesitáis pagar aparte por impresiones o clics.
De aquí se desprenden dos conclusiones prácticas:
- La ventana de oportunidad es TEMPORALMENTE muy barata. Ahora mismo la competencia en el ecosistema ACP es baja, y se puede acceder a segmentos de precio altos sin los presupuestos publicitarios habituales. Es una situación poco común: el tráfico con alta conversión para productos caros (aviación, inmobiliario, productos premium, seguros) puede salir gratis.
- Tiene sentido empezar por las verticales más rentables. Si tenéis acceso a categorías con un alto valor de ticket, es racional conectarlas primero:
- venta/alquiler de aviones, yates y villas;
- venta/alquiler de casas y propiedades inmobiliarias premium;
- joyería, relojes de alta gama, productos y servicios de seguros.
Esto no garantiza «millones rápidos», pero crea una asimetría: quienes primero monten un Product Feed de calidad y un ACP‑backend fiable en segmentos caros obtendrán una ganancia desproporcionadamente alta del canal mientras siga infravalorado y, de facto, gratuito.
2. Arquitectura de referencia de GiftGenius: a grandes rasgos
Empecemos con la vista desde arriba. Recordemos la imagen general de los módulos anteriores: el usuario escribe en ChatGPT, el modelo llama a vuestras herramientas y la capa de commerce vive en un backend aparte.
Formulemos los bloques principales de GiftGenius.
En primer lugar, la UI de ChatGPT y el modelo GPT, que llevan el diálogo con el usuario y, cuando es necesario, conectan el GiftGenius‑App (o incluso funcionan sin App: solo con Product Feed).
En segundo lugar, el widget de GiftGenius (Next.js + Apps SDK), que muestra las tarjetas de regalos y, cuando hace falta, el progreso del checkout. Vive en la sandbox de window.openai y no sabe nada sobre credenciales de pago reales.
En tercer lugar, la capa MCP, que proporciona al modelo herramientas para buscar regalos en el catálogo (Product Feed) y, posiblemente, para leer el historial de pedidos.
En cuarto lugar, el backend de commerce / ACP, que:
- lee el Product Feed como fuente de la verdad sobre productos y SKU;
- implementa la Agentic Checkout Spec (/checkout_sessions, webhooks, estados);
- se comunica con el proveedor de pagos (por ejemplo, Stripe) según la Delegated Payment Spec.
En quinto lugar, las bases de datos del catálogo (si el feed se forma a partir de una BD), de pedidos y de estructuras auxiliares (usuarios, ajustes).
Y, por último, el proveedor de pagos, que almacena y procesa los datos de pago y también envía webhooks con los resultados de los pagos.
Se puede dibujar esquemáticamente así:
graph LR U[Usuario en ChatGPT] --> GPT[Modelo GPT] GPT -->|renderiza| W[GiftGenius Widget
Next.js + Apps SDK] GPT -->|MCP tools| MCP[Servidor MCP
búsqueda de regalos] MCP --> PF["Product Feed
(BD/JSON)"] GPT -->|ACP HTTP| ACP[Backend de comercio GiftGenius
Agentic Checkout] ACP --> ORDERS[Base de pedidos] ACP --> PSP["Proveedor de pagos
(Stripe y otros)"] PSP --> ACP ACP -->|webhooks/eventos| GPT
Este diagrama describe la arquitectura de GiftGenius como un ejemplo de implementación. El formato de Product Feed, el contrato de /checkout_sessions y el protocolo de Delegated Payment forman parte del estándar ACP; la ubicación de servicios, los esquemas de BD y la división en procesos son vuestra elección arquitectónica.
3. Cómo se relacionan lógicamente Product Feed, ACP y el widget
Para no perdernos entre flechas, fijemos una idea simple pero fundamental: tenéis exactamente una sola fuente de la verdad sobre los productos.
En el mundo de GiftGenius, supongamos que es una tabla products + skus en PostgreSQL. A partir de ella:
- Generáis el Product Feed según la especificación de OpenAI (directamente o mediante una exportación).
- Construís un índice de búsqueda para las herramientas MCP (por ejemplo, search_gifts).
- Validáis las solicitudes del ACP‑backend: comprobáis que el sku_id entrante existe y tiene precio y moneda correctos.
De este modo, la búsqueda MCP y el checkout ACP miran los mismos datos, y el widget solo muestra resultados que llegan bien desde las herramientas MCP, bien indirectamente desde ACP (por ejemplo, información de un pedido).
Se puede imaginar como dos «ventanas» al mismo catálogo: una para búsqueda y recomendaciones, y otra para formalizar la compra. Si estas ventanas miran a bases distintas, os espera una vida divertida con desincronizaciones.
4. Modelamos los datos: del Product Feed al pedido
Empecemos con unos tipos de TypeScript sencillos que vivirán en vuestro repositorio de GiftGenius (por ejemplo, en src/domain/commerce.ts). Estos tipos no son una copia literal de las especificaciones, pero reflejan sus ideas principales en una forma cómoda para la aplicación.
// src/domain/commerce.ts
export interface ProductSku {
id: string; // SKU ID estable (coincide con el Product Feed)
title: string; // título legible por humanos
priceCents: number; // precio en céntimos
currency: string; // código ISO, por ejemplo "usd"
}
export type CheckoutStatus = "pending" | "succeeded" | "failed";
export interface CheckoutSession {
id: string;
skuId: string;
totalCents: number;
currency: string;
status: CheckoutStatus;
}
Aquí arrastramos explícitamente en CheckoutSession la referencia a skuId y la moneda/importe fijados. Este es nuestro modelo interno; la Agentic Checkout Spec real es más rica, pero la idea base es la misma: una sesión es «cuánto, por qué y en qué estado».
A continuación, necesitamos el tipo de pedido:
export interface Order {
id: string;
userId: string;
skuId: string;
totalCents: number;
currency: string;
checkoutSessionId: string;
status: "awaiting_payment" | "paid" | "canceled" | "refunded";
}
Aquí se nota la influencia de las entidades comunes del módulo anterior: intent, checkout_session, order. En nuestro proyecto didáctico fusionamos ligeramente intent y order para no multiplicar entidades, pero mantenemos el vínculo con checkoutSessionId.
5. Cómo el widget de GiftGenius «echa un vistazo» al mundo de commerce
Un punto importante: el widget por sí mismo no va a la pasarela de pagos y ni siquiera tiene por qué conocer detalles de ACP; su papel es mostrar al usuario un estado que ha sido calculado y fijado en los backends.
El escenario útil más simple: tras una compra satisfactoria el usuario puede volver al chat y preguntar «Muéstrame mis últimos pedidos en GiftGenius». GPT llamará a una herramienta MCP como get_user_orders, que irá a vuestro backend, y el widget mostrará la lista.
Imaginemos una ruta de API de Next.js que devuelva los pedidos recientes (simplificado):
// app/api/orders/recent/route.ts
import { NextRequest, NextResponse } from "next/server";
import { getRecentOrdersForUser } from "@/lib/orders";
export async function GET(req: NextRequest) {
const userId = req.headers.get("x-giftgenius-user-id")!;
const orders = await getRecentOrdersForUser(userId);
return NextResponse.json({ orders });
}
La función getRecentOrdersForUser ya vive en vuestra capa de commerce, trabaja con la BD y conoce la estructura de los pedidos. El widget, a su vez, puede llamar a esta ruta mediante window.fetch (ya lo hicimos en módulos anteriores) y mostrar tarjetas de compras.
La combinación «herramienta MCP → vuestra API → BD de pedidos → widget» da al usuario la sensación de que el App tiene «memoria» sobre las compras, aunque el widget simplemente está mostrando el estado del backend.
6. Implementación sencilla de un endpoint de ACP al estilo Next.js
Ahora esbocemos cómo puede verse una implementación didáctica de uno de los endpoints clave de ACP: la creación de checkout_session. Según la especificación el contrato es bastante rico, pero para el curso podemos quedarnos con la esencia: llega un skuId, lo comprobamos en el feed/BD, creamos la sesión y devolvemos su ID y el importe.
Supongamos que tenemos la ruta POST /api/checkout-sessions:
// app/api/checkout-sessions/route.ts
import { NextRequest, NextResponse } from "next/server";
import { findSkuById, createCheckoutSession } from "@/lib/checkout";
export async function POST(req: NextRequest) {
const body = await req.json(); // { skuId: string }
const sku = await findSkuById(body.skuId);
if (!sku) {
return NextResponse.json(
{ error: "SKU not found" },
{ status: 400 },
);
}
const session = await createCheckoutSession(sku);
return NextResponse.json({ session });
}
Aquí hay varios puntos importantes.
En primer lugar, es aquí donde la capa de commerce contrasta con el Product Feed/BD: findSkuById debe mirar a la misma fuente de la que se forma el feed. No confiamos en nada que haya llegado «de la nada»: ni de GPT ni del widget.
En segundo lugar, devolvemos solo lo que necesita el cliente ChatGPT/ACP: el ID de la sesión, el importe, la moneda y el estado (por defecto pending o not_ready_for_payment, según la terminología elegida). En ACP real hay más campos, incluida información sobre métodos de pago y fulfillment, pero el ejemplo didáctico se centra en la creación primaria de la sesión.
En tercer lugar, esta ruta es conveniente cubrirla con tests de contrato: si mañana cambia la estructura del Product Feed, los tests de findSkuById y createCheckoutSession deberían detectarlo antes de que ChatGPT empiece a mostrar errores extraños a los usuarios.
7. Relación entre las sesiones de ACP y el proveedor de pagos
Hasta ahora no hemos tocado al proveedor de pagos. En una integración real sucede aproximadamente lo siguiente (escenario simplificado).
Primero, ChatGPT (a través de ACP) llama a vuestro POST /checkout_sessions. Vuestro backend crea una sesión local en su BD. Cuando el usuario confirma el pago en la UI de Instant Checkout, la plataforma solicita al PSP un token de pago delegado (Shared Payment Token) para el merchant y el importe concretos. Ese token os llega en la petición complete (o llamada similar según la Delegated Payment Spec).
Después creáis el pago en el PSP usando el token, sin acceder a los datos de pago reales. El PSP envía un webhook con el resultado; actualizáis el estado del pedido y/o de la sesión de checkout.
En nuestro código didáctico podemos limitarnos a simular este paso. Por ejemplo, la función completeCheckoutSession puede verse así:
// src/lib/checkout.ts
export async function completeCheckoutSession(sessionId: string, spt: string) {
// Aquí, en la realidad, se llama al API del PSP con el token delegado (SPT)
const paymentOk = await mockChargeWithToken(spt);
return paymentOk
? { status: "succeeded" as const }
: { status: "failed" as const };
}
La llamada al PSP y el uso de Shared Payment Token forman parte del estándar de Delegated Payment, mientras que mockChargeWithToken es nuestra capa didáctica que lo simula.
8. Flujo de extremo a extremo en GiftGenius: de la petición al regalo pagado
Ahora juntemos todo como una secuencia de pasos. Esta es la «historia en producción» de GiftGenius por la que combinamos todas las capas. Es importante no mezclar dos mundos distintos, así que los veremos por separado.
Esquema A: sin App, solo Product Feed + ACP
En este escenario tenéis Product Feed y ACP‑backend, pero no tenéis ChatGPT App ni widget. Es el merchant clásico de Instant Checkout.
El usuario escribe en ChatGPT algo como: «Encuentra un regalo digital de hasta 50 $». GPT usa vuestro Product Feed para encontrar los SKU adecuados y los muestra en su UI nativa en forma de tarjetas de compra. Aquí aún no hay ningún React vuestro: las tarjetas las renderiza íntegramente ChatGPT.
El usuario hace clic en el botón «Buy» de una de esas tarjetas. Ese clic lo procesa el propio ChatGPT. La plataforma:
- Forma los line_items en base al Product Feed.
- Llama a vuestro POST /checkout_sessions según la Agentic Checkout Spec.
- Muestra al usuario la UI de Instant Checkout (método de pago, dirección, etc.).
- Tras la confirmación obtiene el Shared Payment Token del PSP y llama a vuestro .../complete.
- Recibe de vosotros el estado final de la checkout_session y, si es necesario, espera el webhook del pedido.
Desde el punto de vista de vuestro código, aquí solo funcionan los endpoints de ACP y el Product Feed. No existe Apps SDK, ni window.openai, ni widget. Y es un escenario ACP totalmente válido y «limpio».
Esquema B: con ChatGPT App y el widget de GiftGenius
Ahora añadimos por encima el ChatGPT App y el widget de GiftGenius. El Product Feed y el ACP‑backend no desaparecen: siguen proporcionando búsqueda y pago. La diferencia es que aparece nuestra propia UI y lógica de pasos dentro del App.
Imaginemos el diálogo: el usuario escribe en ChatGPT: «Encuentra un regalo para mi madre de hasta 50 $». GPT entiende que es una petición de commerce y propone usar el GiftGenius‑App. El widget hace un par de preguntas de aclaración: edad, intereses, país. Después GPT llama a vuestra herramienta MCP search_gifts con filtros, y el servidor MCP consulta el catálogo (BD o índice preparado), encuentra varios SKU adecuados y los devuelve en forma estructurada.
GPT pasa esos datos al widget, y el widget muestra sus tarjetas de regalo personalizadas (componentes de React, carruseles, etc.). Este ya es vuestro diseño y vuestro UX, no el UI de compra estándar de ChatGPT.
Cuando el usuario hace clic en el botón «Comprar» en el widget, ocurre algo distinto al esquema A. Ese clic lo procesa el widget:
- El widget determina qué SKU ha elegido el usuario.
- A través de su API (por ejemplo, POST /api/checkout-sessions) llama a vuestro backend para crear la checkout_session (o para obtener el ID de una sesión ya preparada).
- Luego el widget invoca un método en tiempo de ejecución del Apps SDK similar a:
// Consultad la firma actual del método en la documentación de Apps SDK await window.openai.requestCheckout({ checkoutSessionId: session.id, ... });Esta llamada es una iniciativa del widget. Para ChatGPT es la señal: «Es hora de abrir Instant Checkout para esta checkout_session».
Después la plataforma de ChatGPT ya trabaja de forma muy parecida al esquema A, pero entre bastidores:
- muestra al usuario la UI nativa de Instant Checkout;
- obtiene el Shared Payment Token del PSP;
- llama a vuestro endpoint de ACP para completar la sesión (.../complete);
- participa en la recepción y el procesamiento de webhooks desde vuestro backend.
Es decir, en el esquema B el widget inicia el checkout a través del Apps SDK, y las llamadas de ACP (creación/finalización de la checkout_session) suceden o bien antes (cuando creáis la sesión en el backend), o bien después de requestCheckout, pero siempre en el lado del servidor.
Mientras tanto, el widget puede mostrar en paralelo los pasos de «Tramitación de la compra», estados y la vista previa del pedido, apoyándose en vuestra API (/api/orders/...) y en las herramientas MCP.
Si representamos el esquema B con un diagrama, queda algo así:
sequenceDiagram
participant User as Usuario
participant GPT as ChatGPT / GPT
participant W as GiftGenius Widget
participant MCP as Servidor MCP
participant ACP as Backend de comercio
participant PSP as Proveedor de pagos
User->>GPT: "Encuentra un regalo de hasta 50 $"
GPT->>MCP: search_gifts(...)
MCP-->>GPT: lista de SKU
GPT->>W: datos para renderizar las tarjetas
User->>W: clic "Comprar"
W->>ACP: POST /api/checkout-sessions (skuId)
ACP-->>W: checkout_session (id, importe, moneda)
W->>GPT: window.openai.requestCheckout({ checkoutSessionId })
GPT->>User: UI de Instant Checkout
User->>GPT: confirmación del pago
GPT->>PSP: solicitud de Shared Payment Token
PSP-->>GPT: SPT
GPT->>ACP: complete(sessionId, SPT)
ACP->>PSP: charge(SPT)
PSP-->>ACP: resultado del pago
ACP->>GPT: estado del pedido
GPT->>User: mensaje de pago correcto/incorrecto
Diferencia clave frente al esquema A:
- En A las tarjetas y el botón «Buy» los pinta el propio ChatGPT, y es él quien inicia la llamada a ACP directamente.
- En B las tarjetas y el botón «Comprar» los pinta vuestro widget, y es él quien llama a window.openai.requestCheckout(...). A partir de ahí, ChatGPT habla por debajo con vuestro ACP‑backend y el PSP.
Insight
En su SDK, ChatGPT ya ha indicado que pronto habrá monetización en las aplicaciones. Y así es. Los widgets ya tienen acceso a varios métodos aún no anunciados. Y el más interesante de ellos es requestCheckout().
Su invocación tiene este aspecto:
window.openai.requestCheckout({
id: "checkout_session_123",
payment_provider: {
merchant_id: "stripe",
supported_payment_methods: ["card"]
},
...
}
Muestra un cuadro de diálogo que permite al usuario completar el pago. Así que diseñad vuestra aplicación como si la monetización ya estuviera activada: cuando terminéis el trabajo, así será.
9. Mini‑implementación para el curso: backend monolítico
En los módulos de arquitectura ya surgió la cuestión: ¿hacerlo todo en un solo servicio o dividir desde el principio en servidor MCP, backend de commerce y un servicio aparte para la integración de pagos? Con fines educativos, suele bastar con un «casi monolito»: un único repositorio, un único despliegue, pero la lógica bien separada por capas.
La variante didáctica de GiftGenius puede tener este aspecto: una aplicación Next.js en la que:
- el widget vive en app/widget/page.tsx;
- los endpoints de ACP están en app/api/checkout-sessions y rutas vecinas;
- las herramientas MCP están en app/api/mcp/route.ts o en una carpeta aparte;
- el trabajo con pedidos está en src/lib/orders.ts, src/lib/checkout.ts y módulos cercanos.
Físicamente es un único servidor (especialmente en dev/staging), pero lógicamente ya pensáis en términos de tres roles: UI (widget), MCP (herramientas/recursos para GPT) y ACP (backend de commerce).
Más adelante, en los módulos sobre producción, veréis cómo este «monolito» se divide en varios servicios y entornos, y delante aparece un MCP Gateway. Pero a la altura del módulo 14, este «monolito con capas correctas» ya proporciona una arquitectura muy verosímil.
10. Tarea práctica: vuestra arquitectura alrededor de ACP
Para que todo lo anterior no se quede en teoría, tiene sentido aplicarlo ya a vuestro dominio. En el marco de la lección podéis hacer dos mini‑ejercicios.
En primer lugar, elegid vuestro propio escenario: suscripción SaaS, reservas, reparto de comida, cursos online — cualquier caso con producto/servicio, precio y un checkout razonable. Recordad el modelo por fases: descubrimiento → decisión → checkout → post‑pago.
En segundo lugar, apoyándoos en la arquitectura de GiftGenius, describid libremente: cómo vais a construir el Product Feed (dónde viven los SKU y precios, quién los actualiza), dónde implementaréis el contrato de ACP (servicio aparte o parte del backend existente), cómo conectaréis el proveedor de pagos y cómo vuestro widget (si lo hay) interactuará con todo esto a través de MCP y Apps SDK.
Es útil dejar por escrito si vuestro proyecto usará solo el esquema A (Instant Checkout sin App), solo el esquema B (App + widget) o ambos escenarios a la vez. Incluso este boceto textual de arquitectura reduce mucho el riesgo de sorpresas en la fase de integración real.
11. Errores típicos al integrar Product Feed, ACP y el widget
Error n.º 1: dos catálogos distintos — uno para búsqueda y otro para checkout.
A veces el equipo levanta primero un feed «de búsqueda» rápido para GPT (por ejemplo, un pequeño JSON) y después, aparte, una BD de commerce para pedidos. Si no se vinculan con IDs comunes y una lógica de actualización común, GPT puede proponer al usuario productos que ya no se pueden comprar o a un precio antiguo. El enfoque correcto es una única fuente de la verdad, de la que se formen tanto el Product Feed como las tablas internas para los endpoints de ACP.
Error n.º 2: confiar en los datos que vienen de GPT o del widget.
Cuando en la checkout_session llega un skuId y un precio, apetece creer esos valores: «bueno, GPT no va a mentir». Pero el modelo puede «inventar» o confundir un SKU, y el usuario intentar manipular la solicitud. Si no contrastáis los datos entrantes con el Product Feed/BD, corréis el riesgo de vender otra cosa o por otro precio. Cualquier endpoint de ACP debe empezar validando contra el almacenamiento primario del catálogo.
Error n.º 3: mezclar los roles del widget y del backend de commerce.
A veces, por costumbre, los desarrolladores llaman desde el frontend directamente al SDK de pagos, crean sesiones en Stripe y, en general, viven como en un sitio web normal. En el contexto de ChatGPT Apps eso rompe el modelo de seguridad y contradice ACP: el flujo de pago debe pasar por ChatGPT y por vuestro backend de commerce, y el widget solo debe mostrar estado y enviar eventos (como requestCheckout). Si el widget sabe demasiado del circuito de pago, ganáis complejidad y riesgos.
Error n.º 4: simplificar en exceso el contrato de ACP.
En el ejemplo didáctico dejamos conscientemente solo skuId, importe y estado para no ahogarnos en detalles. El problema aparece cuando ese «contrato demo» se cuela inadvertidamente en producción. De repente falta información para dirección, impuestos, métodos de envío, cupones, y empezáis a «atornillarlos» de forma caótica. Es mejor diseñar los modelos internos con margen para escenarios reales, aunque parte de los campos no se usen al principio.
Error n.º 5: no vincular pedidos con usuarios.
En una demo es fácil limitarse a orderId y skuId sin pensar en cómo volverá el usuario dentro de una semana a pedir: «Muéstrame mis compras». Si no se incluye desde el principio un userId (u otro identificador estable) en el pedido y en la sesión de checkout, luego tocará hacer migraciones y puentes complejos. La arquitectura de commerce alrededor de ChatGPT casi siempre presupone que GPT podrá vincular el diálogo actual con el historial de pedidos del usuario — conviene tenerlo en cuenta desde el principio.
Error n.º 6: subestimar la importancia de los webhooks y la idempotencia.
En la lección solo hablamos de webhooks; los veréis en profundidad en módulos siguientes. Es fácil pensar: «bueno, el webhook llegará una vez, actualizamos el pedido y ya». En la práctica, las pasarelas reintentan eventos y la red pierde respuestas. Si no diseñáis pedidos y sesiones de checkout como estructuras idempotentes (por checkoutSessionId o paymentId), podéis acabar con cobros dobles, pedidos duplicados y discrepancias no evidentes entre el PSP y vuestra BD.
Error n.º 7: ignorar restricciones y políticas en el Product Feed.
En la carrera por un feed de demo rápido es fácil olvidar las restricciones de edad, disponibilidad por país, categorías prohibidas y otras «minucias». Luego resulta que GPT propone al usuario un producto que no se puede vender en su región o edad. Los campos relacionados con políticas y restricciones hay que diseñarlos y rellenarlos desde el principio, incluso si por ahora solo vendéis regalos digitales inofensivos.
GO TO FULL VERSION