# Envía a MailerLite las suscripciones de tu propio formulario de newsletter

> Conecta tu propio formulario de suscripción con MailerLite: un relay añade a los lectores nuevos como no confirmados para el doble opt-in y nunca pide a un suscriptor que confirme dos veces.

Publicado el 2026-10-25 · https://ikiform.com/es/guides/newsletter-signup/mailerlite

Envía tu propio formulario a Ikiform y apunta el webhook a un relay que llame a la API de MailerLite. El relay busca primero la dirección: un lector nuevo se crea como `unconfirmed`, lo que hace que MailerLite envíe su email de doble opt-in cuando el ajuste de la API está activado, y un suscriptor existente solo recibe el nuevo grupo. Esa búsqueda es lo que evita que a un suscriptor confirmado se le pida confirmar otra vez.

## Qué cambia con MailerLite

El endpoint de crear suscriptor de MailerLite es un upsert: un `POST` a `/api/subscribers` crea un suscriptor nuevo o actualiza uno existente, y responde `201` o `200`. No es destructivo, así que los grupos y campos que no incluyas se quedan como estaban. El problema es `status`. Con el ajuste de cuenta **Double opt-in for API and integrations** activado, MailerLite envía una confirmación a los nuevos suscriptores de la API. Un suscriptor existente activo o dado de baja solo la recibe cuando la llamada envía `status: "unconfirmed"`.

La ayuda de MailerLite dice que los suscriptores existentes activos o dados de baja no reciben el email de confirmación a menos que la llamada incluya `"status": "unconfirmed"`. Así que un relay que siempre envía `unconfirmed` convierte cada suscripción repetida de un lector fiel en una nueva petición de confirmación. La solución es buscar la dirección antes de decidir qué enviar:

Diagrama: Cómo decide el relay qué enviar a MailerLite

1. El relay verifica el webhook de Ikiform.
2. Pide a MailerLite el suscriptor por email.
3. No existe: lo crea con estado unconfirmed y el grupo de la ubicación, y MailerLite envía el email de confirmación.
4. Existe y está activo o sin confirmar: añade el grupo sin estado, así que nada de su confirmación cambia.
5. Existe y se dio de baja: no hace nada, así que una suscripción nunca deshace en silencio una baja.

Dos llamadas a la API por suscripción, y la segunda depende de lo que encontró la primera.

## Configura MailerLite

1. En MailerLite, abre los ajustes de suscripción y activa **Double opt-in for API and integrations**. Edita ahí el email de confirmación; MailerLite envía el mismo a todos los suscriptores añadidos mediante la API.
2. Crea un grupo por ubicación, como "Website footer" y "Blog posts", y apunta el id de cada grupo.
3. En **Integrations**, crea un token de API y guárdalo para el entorno del relay.

> Las preguntas frecuentes de precios de MailerLite dicen que el acceso a la API está limitado en su plan más bajo. Comprueba que el token puede crear suscriptores en tu plan antes de confiar en él.

## El relay

Esto es un servidor Express. Lee el cuerpo sin procesar como texto, porque la firma cubre los bytes exactos que envió Ikiform, y analizar el JSON primero los cambiaría.

`server.ts`:

```ts
import express from "express";
import { verifyWebhook, WebhookVerificationError } from "@ikiform/sdk/webhooks";

const API = "https://connect.mailerlite.com/api";
const GROUPS: Record<string, string> = {
  footer: process.env.MAILERLITE_GROUP_FOOTER!,
  post: process.env.MAILERLITE_GROUP_POST!,
};

function mailerlite(path: string, init: RequestInit = {}) {
  return fetch(`${API}${path}`, {
    ...init,
    headers: {
      Authorization: `Bearer ${process.env.MAILERLITE_API_KEY}`,
      "Content-Type": "application/json",
      Accept: "application/json",
    },
  });
}

async function subscribe(email: string, name: string | undefined, source: string) {
  const found = await mailerlite(`/subscribers/${encodeURIComponent(email)}`);
  if (found.status !== 200 && found.status !== 404) return found;

  const groups = [GROUPS[source] ?? process.env.MAILERLITE_GROUP_FOOTER!];
  const fields = name ? { name } : {};

  if (found.status === 404) {
    return mailerlite("/subscribers", {
      method: "POST",
      body: JSON.stringify({ email, fields, groups, status: "unconfirmed" }),
    });
  }

  const existing = await found.json();
  if (existing.data.status === "unsubscribed") return new Response(null, { status: 208 });
  return mailerlite("/subscribers", { method: "POST", body: JSON.stringify({ email, fields, groups }) });
}

const app = express();

app.post("/hooks/mailerlite", express.text({ type: "application/json", limit: "512kb" }), async (req, res) => {
  let event;
  try {
    event = await verifyWebhook({ payload: req.body, headers: req.headers, secret: process.env.IKIFORM_WEBHOOK_SECRET! });
  } catch (error) {
    if (error instanceof WebhookVerificationError) return res.status(400).send(error.reason);
    return res.status(500).end();
  }
  if (event.type !== "submission.created") return res.status(204).end();

  const { email, first_name, consent, source } = event.data.fields;
  if (consent !== true || typeof email !== "string") return res.status(200).send("Skipped");

  const answer = await subscribe(
    email,
    typeof first_name === "string" ? first_name : undefined,
    typeof source === "string" ? source : "footer",
  );
  if (answer.status === 208) return res.status(200).send("Unsubscribed earlier, left alone");
  if (answer.status === 429) {
    return res.status(503).set("retry-after", answer.headers.get("retry-after") ?? "60").send("MailerLite rate limit");
  }
  if (!answer.ok) return res.status(502).send(`MailerLite answered ${answer.status}: ${await answer.text()}`);
  res.status(204).end();
});

app.listen(Number(process.env.PORT ?? 3000));
```

- MailerLite recibe el token como `Authorization: Bearer`. La URL base es `https://connect.mailerlite.com/api`.
- `GET /api/subscribers/{email}` acepta un email o un id y responde `404` cuando el suscriptor no existe.
- `groups` recibe ids de grupos que ya existen. Un id incorrecto se rechaza con `422`, que el relay transmite como `502` con el mensaje de MailerLite.
- `fields.name` es el campo de nombre por defecto de MailerLite. Los campos personalizados deben existir en MailerLite antes de enviarlos.
- El `208` es una marca interna para un lector dado de baja. Ikiform ve `200` y una nota en el registro de entregas.

Despliégalo en cualquier sitio que te dé una URL HTTPS pública en el puerto 443, añade esa URL en **Webhooks** en Ikiform y pon el secreto `whsec_` en `IKIFORM_WEBHOOK_SECRET`. La [documentación de webhooks](https://ikiform.com/es/docs/webhooks.md) cubre los reintentos y el payload, y [tu propio servidor](https://ikiform.com/blog/form-submissions-to-your-own-server.md) tiene la misma configuración de Express con una base de datos.

## Dónde vive el registro del consentimiento

La llamada de creación de MailerLite acepta `subscribed_at`, `ip_address`, `opted_in_at` y `optin_ip`. Deja fuera los campos de IP. El webhook de Ikiform nunca incluye la dirección IP del visitante ni su hash, así que el relay no tiene nada verdadero que enviar, y un valor inventado es peor que ninguno.

El registro de la suscripción se queda en Ikiform: el envío conserva `consent: true` con su marca de tiempo, origen, referrer y país. El registro de la confirmación vive en MailerLite, que anota cuándo hizo clic el lector en el enlace. Entre los dos puedes mostrar cuándo alguien marcó la casilla y cuándo demostró que la dirección era suya. Exporta la parte de Ikiform como CSV desde **Submissions** cuando la necesites.

## Límites de frecuencia

El límite global de la API de MailerLite es de 120 peticiones por minuto. El relay hace dos por suscripción, así que caben unas 60 suscripciones por minuto. Por encima de eso, MailerLite responde `429`, el relay responde `503` con `Retry-After`, e Ikiform vuelve a intentarlo más tarde con la misma entrega.

| MailerLite responde | El relay responde | Ikiform |
| --- | --- | --- |
| `201` o `200` | `204` | Entrega correcta |
| `429` | `503` con `Retry-After` | Espera y reintenta |
| `401` | `502` | Reintenta. Arregla el token y luego usa **Retry now** en las entregas fallidas |
| `422` | `502` con los errores | Reintenta. Normalmente es un id de grupo o un nombre de campo incorrecto |

## Errores comunes

- **No envíes `status: "active"`.** Marca a la persona como suscrita, y la documentación de MailerLite no dice si aun así sale una confirmación. Prueba con el estado que envíes.
- **Volver a suscribir es una decisión.** MailerLite tiene un flag `resubscribe` para quienes se dieron de baja. Envíalo solo cuando tu formulario lo diga, y cuando el lector sepa que vuelve a darse de alta.
- **El interruptor importa.** MailerLite solo envía un email de confirmación a las suscripciones de la API cuando **Double opt-in for API and integrations** está activado.
- **Un solo email de confirmación.** El email de doble opt-in de la API es el mismo para todas las suscripciones de la API. Si necesitas un texto distinto por ubicación, usa formularios de MailerLite separados.
- **Duplicados en Ikiform.** Ikiform guarda cada envío aceptado, mientras que MailerLite guarda un suscriptor por email. Cuenta los suscriptores en MailerLite, no en el panel de Ikiform.

## Comprueba que funciona

1. Envía una prueba desde el endpoint en Ikiform. La entrega muestra `204`.
2. Suscríbete con una dirección nueva tuya. MailerLite muestra el suscriptor como no confirmado en el grupo del footer, y llega el email de confirmación.
3. Confírmalo y vuelve a suscribirte desde un post del blog. El suscriptor sigue activo, se une al segundo grupo y no recibe un nuevo email de confirmación.
4. Da de baja esa dirección en MailerLite y suscríbete una vez más. El registro de entregas muestra la nota de baja, y MailerLite sigue mostrándolo como dado de baja.

## Preguntas

### ¿Puedo usar mi propio formulario HTML con MailerLite en lugar de su embed?

Sí. Envía el formulario a Ikiform y deja que un relay añada cada suscripción mediante la API de MailerLite con el grupo correcto. El formulario se queda en tu markup y MailerLite sigue enviando la newsletter.

### ¿Por qué MailerLite no envía un email de confirmación a las suscripciones de la API?

O bien Double opt-in for API and integrations está desactivado en los ajustes de suscripción de MailerLite, o bien el relay creó el suscriptor como activo. Mantén el ajuste activado, envía el estado unconfirmed y prueba con una dirección tuya.

### ¿Recibirá dos emails de confirmación un suscriptor que se suscribe dos veces?

No con este relay. Primero busca la dirección y solo envía unconfirmed para un suscriptor nuevo. Un suscriptor existente se añade al nuevo grupo y no cambia nada más.

### ¿Cómo pongo las suscripciones del footer y del blog en grupos distintos de MailerLite?

Da a cada ubicación un valor distinto en el input oculto source del formulario y relaciona cada valor con un id de grupo de MailerLite en el relay. Un suscriptor existente que se suscribe desde una segunda ubicación también se une a ese grupo, y conserva el primero.

### ¿Ikiform envía algo al suscriptor?

No. Ikiform nunca envía email a la persona que envía un formulario. MailerLite envía la confirmación, cada newsletter y el enlace para darse de baja.

## Más guías

- [Formulario de suscripción a newsletter](https://ikiform.com/es/guides/newsletter-signup.md): Crea un formulario de suscripción a tu newsletter con tu propio markup, registra el consentimiento, bloquea los registros de bots y pasa cada suscriptor a Kit, MailerLite, beehiiv o cualquier herramienta.
- [Doble opt-in](https://ikiform.com/es/guides/newsletter-signup/double-opt-in.md): Ikiform no envía emails de confirmación, así que el doble opt-in se hace en tu herramienta de email: un relay añade cada suscripción como no confirmada y la herramienta envía el enlace.
- [Kit (ConvertKit)](https://ikiform.com/es/guides/newsletter-signup/kit.md): Conecta tu propio formulario de newsletter con Kit mediante un relay que crea el suscriptor, lo añade a un formulario de Kit para el incentive email y etiqueta la ubicación.
- [beehiiv](https://ikiform.com/es/guides/newsletter-signup/beehiiv.md): Conecta tu propio formulario de suscripción con beehiiv: un relay crea cada suscripción con el doble opt-in activado, la ubicación como fuente UTM y la página como referrer.
- [Sitio estático](https://ikiform.com/es/guides/newsletter-signup/static-site.md): Añade un formulario de suscripción a tu newsletter en un sitio estático con Hugo, Jekyll, Eleventy o Astro, deja la API key fuera de la página y confirma en la herramienta.
- [Formulario de newsletter en Next.js](https://ikiform.com/es/guides/newsletter-signup/nextjs.md): Un formulario de newsletter en el footer de Next.js: una server action con comprobación de consentimiento y Turnstile que envía a Ikiform, más un route handler que añade a los lectores a Kit.
