Manual para crear tu propia invitación — Madify Invita
Este documento explica cómo armar tu propia página de invitación (a mano o pidiéndosela a una inteligencia artificial como Claude) para publicarla en Madify Invita. Tu página recibe los datos de tu evento automáticamente y las confirmaciones de asistencia llegan a tu panel.
Si vas a usar una IA: copia este documento completo en la conversación y pídele tu diseño. Al final hay un bloque «Prompt para la IA» listo para usar.
1. Qué vas a entregar
Un archivo ZIP con tu sitio:
mi-invitacion.zip
├── index.html ← obligatorio (en la raíz del ZIP o dentro de UNA carpeta)
├── css/estilos.css
├── js/app.js
└── img/foto.webp
index.htmles la portada. Puedes tener más páginas (galeria.html); también reciben los datos.- Usa rutas relativas:
img/foto.webp, nunca/img/foto.webpni rutas de tu computadora. - Todo en UTF-8.
2. Reglas del ZIP
- Extensiones permitidas: avif, css, eot, gif, htm, html, ico, jpeg, jpg, js, json, m4a, map, mjs, mp3, mp4, ogg, otf, png, svg, ttf, txt, wav, webm, webmanifest, webp, woff, woff2.
- Máximo 50 MB comprimido, 200 MB descomprimido y 500 archivos.
- Se ignoran
__MACOSX/,.DS_Storey archivos ocultos. No se aceptan enlaces simbólicos ni rutas con... - Optimiza las imágenes (WebP o JPEG, menos de 400 KB cada una): la mayoría de tus invitados abrirá la invitación desde el celular.
- Si la página tiene un error de sintaxis en las variables, el sistema te dice el archivo y la línea.
3. Datos dinámicos (variables)
Tu HTML se procesa con el motor de plantillas de Django. Escribe {{ variable }} donde quieras que aparezca un dato y {% if … %}…{% endif %} para mostrar algo solo si existe.
Llaves principales:
| Variable | Qué es |
|---|---|
event |
Datos del evento (tabla «event») |
guest |
El invitado del link personal, o vacío en el link general (tabla «guest») |
rsvp |
La respuesta previa de ese invitado, o vacío (tabla «rsvp») |
rsvp_config |
Configuración del formulario de confirmación (tabla «rsvp_config») |
theme |
Solo en diseños del catálogo: las opciones que personaliza el cliente ({{ theme.<clave> }}) y theme.design (slug, name, version). Vacío en un ZIP propio |
now |
Fecha y hora actual del servidor |
event
| Variable | Tipo | Descripción | Ejemplo |
|---|---|---|---|
event.title |
texto | Título del evento | Boda de Ana y Luis |
event.slug |
texto | Path del evento en la URL | boda-ana-y-luis |
event.type |
texto | Tipo (clave): boda, xv_anos, bautizo, primera_comunion, baby_shower, cumpleanos, fiesta, graduacion, corporativo, otro | boda |
event.type_label |
texto | Tipo legible | Boda |
event.honorees |
texto | Festejado(s) | Ana y Luis |
event.hosts |
texto | Anfitriones / papás / padrinos | Familia López |
event.description |
texto | Mensaje principal (usa | linebreaksbr para saltos de línea) |
event.starts_at |
fecha y hora | Inicio del evento (usa el filtro date) | {{ event.starts_at|date:"l j \d\e F" }} → sábado 24 de octubre |
event.ends_at |
fecha y hora | Fin del evento (puede estar vacío) | |
event.dress_code |
texto | Código de vestimenta | Formal |
event.contact_phone |
texto | WhatsApp del anfitrión (con lada) | 5214431234567 |
event.whatsapp_url |
URL | Link directo a WhatsApp del anfitrión (vacío si no hay teléfono) | https://wa.me/5214431234567 |
event.rsvp_deadline |
fecha | Fecha límite para confirmar (puede estar vacía) | {{ event.rsvp_deadline|date:"j \d\e F" }} |
event.rsvp_open |
sí/no | Si todavía se puede confirmar | True |
event.allow_public_rsvp |
sí/no | Si se puede confirmar sin link personal | True |
event.allow_children |
sí/no | Si la invitación admite niños | True |
event.locations |
lista | Ubicaciones en orden (ver tabla de ubicaciones) | {% for loc in event.locations %}…{% endfor %} |
event.main_location |
ubicación | La primera ubicación (o vacío) | {{ event.main_location.name }} |
event.links |
lista | Links del evento (ver tabla de links) | {% for link in event.links %}…{% endfor %} |
event.gift_links |
lista | Solo los links de tipo «mesa de regalos» | {{ event.gift_links.0.url }} |
event.extra |
diccionario | Datos libres que captura el anfitrión | {{ event.extra.hashtag }} |
event.url |
texto | Ruta relativa de la invitación | /boda-ana-y-luis/ |
event.public_url |
URL | Dirección completa de la invitación (dominio propio si lo hay) | https://invite.madify.mx/boda-ana-y-luis/ |
Cada ubicación (event.locations, event.main_location)
| Variable | Tipo | Descripción | Ejemplo |
|---|---|---|---|
loc.kind |
texto | Clave: ceremonia, recepcion, evento, otro | ceremonia |
loc.kind_label |
texto | Tipo legible | Ceremonia |
loc.name |
texto | Nombre del lugar (puede estar vacío) | Parroquia de San José |
loc.address |
texto | Dirección | Centro, Morelia |
loc.maps_url |
URL | Link de Google Maps tal cual lo capturaron (puede estar vacío) | https://maps.app.goo.gl/… |
loc.maps_link |
URL | maps_url o, si está vacío, una búsqueda de Google Maps con lugar + dirección | https://www.google.com/maps/search/?api=1&query=… |
loc.starts_at |
fecha y hora | Hora de esta ubicación (puede estar vacía) | {{ loc.starts_at|time:"g:i a" }} |
loc.notes |
texto | Notas | Estacionamiento en la parte trasera |
Cada link (event.links, event.gift_links)
| Variable | Tipo | Descripción | Ejemplo |
|---|---|---|---|
link.kind |
texto | Clave: regalos, hospedaje, transmision, playlist, fotos, otro | regalos |
link.kind_label |
texto | Tipo legible | Mesa de regalos |
link.label |
texto | Texto del botón | Ver mesa de regalos |
link.url |
URL | Destino | https://mesaderegalos.liverpool.com.mx/… |
guest (solo cuando se abre con link personal)
| Variable | Tipo | Descripción | Ejemplo |
|---|---|---|---|
guest.name |
texto | Nombre de la invitación (persona, pareja o familia) | Familia Pérez |
guest.max_adults |
número | Lugares para adultos | 2 |
guest.max_children |
número | Lugares para niños | 1 |
guest.max_total |
número | Total de lugares | 3 |
guest.token |
texto | Código del link personal (?i=) | VoVZx4P4BgNt |
rsvp (la respuesta previa de ese invitado, si ya confirmó)
| Variable | Tipo | Descripción | Ejemplo |
|---|---|---|---|
rsvp.name |
texto | Nombre con el que confirmó | Laura Pérez |
rsvp.attending |
sí/no | Si asiste | True |
rsvp.adults |
número | Adultos confirmados | 2 |
rsvp.children |
número | Niños confirmados | 1 |
rsvp.message |
texto | Mensaje que dejó | ¡Felicidades! |
rsvp.attendees |
lista | Acompañantes: name, type (adult/child), age | {% for a in rsvp.attendees %}{{ a.name }}{% endfor %} |
rsvp.updated_at |
fecha y hora | Última actualización de su respuesta |
rsvp_config
| Variable | Tipo | Descripción | Ejemplo |
|---|---|---|---|
rsvp_config.endpoint |
URL | A dónde se manda la confirmación (POST JSON) | /api/v1/public/events/boda-ana-y-luis/rsvp/ |
rsvp_config.token |
texto | Token del invitado (vacío en el link general) | |
rsvp_config.mode |
texto | guest (link personal), public (link general), invite_only (solo con link personal) o closed (ya cerró) | guest |
rsvp_config.max_adults |
número | Máximo de adultos que puede confirmar quien abre la página | 2 |
rsvp_config.max_children |
número | Máximo de niños | 1 |
rsvp_config.allow_children |
sí/no | Si puede confirmar niños | True |
rsvp_config.deadline |
texto | Fecha límite ISO (o vacío) | 2026-10-15 |
Filtros útiles
{{ event.starts_at|date:"l j \d\e F \d\e Y" }} → sábado 24 de octubre de 2026
{{ event.starts_at|date:"g:i a" }} → 1:00 p.m.
{{ event.starts_at|date:"c" }} → 2026-10-24T13:00:00-06:00 (para cuentas regresivas en JS)
{{ event.description|linebreaksbr }} → respeta los saltos de línea
{{ event.honorees|upper }} → ANA Y LUIS
{{ guest.max_adults|pluralize:"es" }} → «es» si es plural (lugar/lugares)
{{ event.extra.hashtag|default:"#AnayLuis" }} → valor por defecto si está vacío
Ejemplos:
<h1>{{ event.honorees }}</h1>
<p>{{ event.starts_at|date:"l j \d\e F" }} · {{ event.starts_at|date:"g:i a" }}</p>
{% if guest %}
<p>¡Hola, {{ guest.name }}! Reservamos {{ guest.max_adults }} lugar{{ guest.max_adults|pluralize:"es" }}.</p>
{% endif %}
{% for loc in event.locations %}
<h3>{{ loc.kind_label }}: {{ loc.name }}</h3>
<p>{{ loc.address }}</p>
{% if loc.maps_link %}<a href="{{ loc.maps_link }}">Ver mapa</a>{% endif %}
{% endfor %}
{% for link in event.gift_links %}<a href="{{ link.url }}">{{ link.label }}</a>{% endfor %}
Si tu JavaScript usa llaves dobles (Vue, Handlebars, etc.), enciérralo en {% verbatim %}…{% endverbatim %} para que no se procese.
4. Confirmación de asistencia
Opción A — formulario listo
<section id="confirmar">
{% rsvp_form %}
</section>
{% rsvp_script %} {# antes de </body> #}
Genera un formulario completo (nombre, asiste sí/no, adultos, niños, nombres de acompañantes, mensaje) que puedes estilizar con CSS: .rsvp-form, .rsvp-field, .rsvp-submit, .rsvp-success, .rsvp-error.
Opción B — tu propio formulario
Pon data-rsvp en tu <form> y usa estos name en los campos:
Campo (name) |
Qué es |
|---|---|
name |
Nombre de quien confirma (obligatorio en el link general) |
attending |
Asiste: radio/select/checkbox con valores yes/no (también si/no, true/false) |
adults |
Número de adultos |
children |
Número de niños |
guests |
Total de personas (alternativa a adults/children; se cuentan como adultos) |
message |
Mensaje para los anfitriones |
phone |
Teléfono (opcional) |
email |
Correo (opcional) |
website |
Campo trampa anti-spam: agrégalo oculto y déjalo vacío |
Atributos que entiende el script:
| Atributo | Para qué |
|---|---|
data-rsvp |
En el |
data-rsvp-attendees |
Contenedor donde se generan los campos de nombre por cada adulto/niño |
data-rsvp-when-attending |
Visible solo si responde que sí asiste |
data-rsvp-when-declined |
Visible solo si responde que no |
data-rsvp-children |
Se oculta si la invitación no incluye niños |
data-rsvp-success |
Mensaje de éxito (se muestra al confirmar) |
data-rsvp-error |
Mensaje de error |
data-rsvp-closed |
Visible si la confirmación ya cerró |
data-rsvp-invite-only |
Visible si solo se acepta con link personal |
data-success-yes / data-success-no |
En el |
<form data-rsvp data-success-yes="¡Gracias! Nos vemos pronto." data-success-no="¡Te extrañaremos!">
<input name="name" placeholder="Tu nombre" required>
<label><input type="radio" name="attending" value="yes"> Sí asistiré</label>
<label><input type="radio" name="attending" value="no"> No podré ir</label>
<div data-rsvp-when-attending hidden>
<input type="number" name="adults" min="1" value="1">
<input type="number" name="children" min="0" value="0" data-rsvp-children>
<div data-rsvp-attendees></div>
</div>
<textarea name="message"></textarea>
<input type="text" name="website" tabindex="-1" autocomplete="off" style="position:absolute;left:-9999px">
<button type="submit">Enviar</button>
<p data-rsvp-success hidden></p>
<p data-rsvp-error hidden></p>
</form>
{% rsvp_script %}
- Con link personal (
?i=…) el nombre se llena solo, se respetan los lugares del invitado y, si ya había confirmado, su respuesta aparece para modificarla. - Sin link personal (link general) se pide el nombre y se respetan los límites del evento.
- Los límites se validan también en el servidor: no se puede confirmar de más aunque alguien modifique la página.
5. Página de ejemplo completa (mínima)
<!doctype html>
<html lang="es-MX">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{ event.title }}</title>
<link rel="stylesheet" href="css/estilos.css">
</head>
<body>
<header>
<p class="eyebrow">{{ event.type_label }}</p>
<h1>{{ event.honorees }}</h1>
<p>{{ event.starts_at|date:"l j \d\e F \d\e Y" }} · {{ event.starts_at|date:"g:i a" }}</p>
{% if guest %}<p class="hola">¡Hola, {{ guest.name }}!</p>{% endif %}
</header>
{% if event.description %}<section><p>{{ event.description|linebreaksbr }}</p></section>{% endif %}
<section>
{% for loc in event.locations %}
<article>
<h2>{{ loc.kind_label }}</h2>
{% if loc.name %}<h3>{{ loc.name }}</h3>{% endif %}
<p>{{ loc.address }}{% if loc.starts_at %} · {{ loc.starts_at|time:"g:i a" }}{% endif %}</p>
{% if loc.maps_link %}<a href="{{ loc.maps_link }}" target="_blank" rel="noopener">Cómo llegar</a>{% endif %}
</article>
{% endfor %}
</section>
{% if event.gift_links %}
<section>
<h2>Mesa de regalos</h2>
{% for link in event.gift_links %}<a href="{{ link.url }}" target="_blank" rel="noopener">{{ link.label }}</a>{% endfor %}
</section>
{% endif %}
<section id="confirmar">
<h2>Confirma tu asistencia</h2>
{% if event.rsvp_deadline %}<p>Antes del {{ event.rsvp_deadline|date:"j \d\e F" }}.</p>{% endif %}
{% rsvp_form %}
</section>
{% rsvp_script %}
</body>
</html>
6. Prompt para la IA
Copia y pega esto después de este manual, cambiando lo que está entre corchetes:
Con base en el manual anterior, crea mi invitación digital para [tipo de evento: boda, XV años, bautizo…]
con estilo [describe: elegante, minimalista, floral, rústico, colores dorado y verde olivo…].
Requisitos:
- Entrégame el contenido de cada archivo y la estructura del ZIP (index.html en la raíz, css/, img/).
- Usa SOLO las variables del manual ({{ event.… }}, {{ guest.… }}); no escribas datos fijos de fecha, lugar o nombres.
- Incluye una sección de confirmación con {% rsvp_form %} (o un formulario data-rsvp) y {% rsvp_script %} antes de </body>.
- Diseño mobile first, que cargue rápido (sin frameworks pesados); fuentes de Google Fonts permitidas.
- No cargues scripts de terceros (salvo Google Fonts) ni envíes datos a otros servidores.
- Si usas JavaScript con llaves dobles, enciérralo en {% verbatim %}.
- Rutas relativas para imágenes y CSS. Indica qué imágenes debo agregar y de qué tamaño.
Secciones que quiero: [portada con nombres y fecha, cuenta regresiva, mensaje, ubicaciones con mapa, mesa de regalos, galería, confirmación…].
7. Antes de enviar (checklist)
- [ ]
index.htmlen la raíz del ZIP y rutas relativas. - [ ] Probaste la página abriéndola en el celular (los datos aparecen como
{{ … }}hasta que se publica: es normal). - [ ] La sección de confirmación usa
{% rsvp_form %}o unform data-rsvpy{% rsvp_script %}. - [ ] Imágenes optimizadas y el ZIP pesa menos de 50 MB.
- [ ] Sin scripts externos ni formularios que manden datos a otros sitios.
8. Cómo enviarlo
- Entra a tu panel: https://invite-app.madify.mx/admin/ → Mi sitio → Enviar sitio.
- Elige tu evento y sube el ZIP. Si algo no cumple las reglas, verás el error al momento.
- Lo revisamos (normalmente en menos de 24 horas) y te avisamos por correo cuando esté publicado. Si necesita cambios, te decimos cuáles.
Necesitas un plan que incluya sitio propio. Consulta los planes en https://invite.madify.mx/precios/.
9. Qué no se permite
- Scripts que capturen datos de tus invitados y los manden a otros servidores, o formularios que apunten a otros sitios.
- Contenido ilegal, engañoso u ofensivo, o que use marcas o imágenes sin permiso.
- Intentar leer archivos del servidor o romper el sistema (la página se rechaza).
¿Dudas? .