Zot Waitlist - Mejores Prácticas

Integra una lista de espera de Zot en cualquier aplicación TypeScript, React o Next.js usando el SDK oficial `@zot-core/sdk` y la herramienta de línea de comandos `@zot-core/cli`. Usa este skill cada vez que el usuario pida "agregar una lista de espera", "crear una lista de espera", "recopilar registros", "agregar acceso anticipado", "integrar Zot", "construir una página de próximamente con captura de correo electrónico", o conecte la captura de correo electrónico a Zot.

¿Qué es Zot Waitlist - Mejores Prácticas?

Este skill proporciona instrucciones detalladas y mejores prácticas para integrar una lista de espera de Zot en aplicaciones TypeScript, React o Next.js. Utiliza el SDK oficial `@zot-core/sdk` y la herramienta CLI `@zot-core/cli` para simplificar el proceso, evitando llamadas HTTP directas a la API de Zot. El skill cubre dos patrones principales: un patrón del lado del servidor usando `ZotSDK` para API routes o server actions, y un patrón del lado del cliente usando el hook `useAddUser` de `@zot-core/sdk/react`, que gestiona automáticamente el estado de carga, error y registro exitoso. También incluye reglas estrictas, como nunca envolver el hook en bibliotecas externas de gestión de estado, nunca exponer claves de API de servidor en el cliente, y manejar adecuadamente los errores `ZotAPIError`. El skill proporciona una lista de verificación completa para asegurar una integración correcta antes de finalizar.

Compatible con~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/launch-waitlist-zot/zot-skills/tree/HEAD/skills/waitlist

Installed? Explore more Productividad y colaboración skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

Preguntar en tu IA favorita

Abre un nuevo chat con esta habilidad de agente ya precargada.

Documentación

¿Qué hace Zot Waitlist - Mejores Prácticas?

Este skill te indica cómo integrar correctamente una lista de espera de Zot. Sigue estas reglas. No inventes alternativas.

TL;DR - el camino más corto

# 1. Instala el SDK
npm install @zot-core/sdk

# 2. Crea la lista de espera y persiste su ID en .env.local
npx @zot-core/cli waitlist create --name "Acceso Anticipado" --write-env .env.local --public

# 3. Construye la UI (ver Patrón B más abajo) usando `useAddUser` de "@zot-core/sdk/react"

Esa es la integración completa para un proyecto Next.js. No agregues TanStack Query, no escribas un manejador POST personalizado, no llames a la API con fetch en bruto. Todo lo que necesitas está a continuación.

Reglas no negociables

  1. Usa el SDK oficial. Nombre del paquete: @zot-core/sdk. Nunca llames a https://api.zot.so con fetch, axios o similar en bruto.
  2. Elige el punto de entrada correcto según dónde se ejecute el código:
    • Servidor, ruta de API, cron, script, función edge -> import { ZotSDK } from "@zot-core/sdk"
    • Componente React que se ejecuta en el navegador -> import { useAddUser } from "@zot-core/sdk/react"
  3. Nunca envuelvas useAddUser en TanStack Query, SWR, useState, Zustand o un reducer personalizado. El hook ya expone isPending, isUserRegistered, data, error, isError y reset. Reutilizar su estado es todo el propósito.
  4. Nunca envíes una clave API del lado del servidor al cliente. Para código del navegador, usa una clave con permisos solo de registro y exponla como NEXT_PUBLIC_ZOT_API_KEY (o el equivalente de entorno público de tu framework).
  5. Maneja siempre ZotAPIError. Muestra un texto amigable para el usuario en caso de 409 (ya registrado) y 429 (límite de velocidad).

Instalación

npm install @zot-core/sdk
# o
pnpm add @zot-core/sdk
# o
yarn add @zot-core/sdk

No se requieren dependencias adicionales para uso del servidor. Para el hook, react >= 18 debe estar ya instalado (el SDK lo marca como dependencia opcional).

Obtén tus credenciales

Necesitas dos cosas:

  1. Clave API - el camino más rápido es npx @zot-core/cli login, que autentica al usuario y escribe una nueva ZOT_API_KEY en el archivo de entorno local. Alternativamente, genera una manualmente desde el panel de control de Zot en https://app.zot.so/app/api-keys. Crea una clave para uso del servidor y, si planeas llamar desde el navegador, una segunda clave con permisos solo de registro.
  2. ID de lista de espera - tiene el formato wl_abc123.
# Autenticar y persistir ZOT_API_KEY en .env.local (o .env si pasas --env .env)
npx @zot-core/cli login

Crear la lista de espera con @zot-core/cli (recomendado)

Si el usuario no tiene ya una lista de espera, usa el CLI oficial de Zot. Llama a la API de Zot con la ZOT_API_KEY del usuario y escribe el ID resultante directamente en el archivo de entorno para que nunca tengas que copiarlo y pegarlo.

Paquete: @zot-core/cli. No lo confundas con @zot-core/agents - @zot-core/agents solo instala esta guía de agente en un repositorio; @zot-core/cli se comunica con la API de Zot.

# Asegúrate de que ZOT_API_KEY esté definida (en el shell, en .env.local o en .env)
npx @zot-core/cli waitlist create \
  --name "Acceso Anticipado" \
  --write-env .env.local \
  --public

Lo que esto hace:

  • Llama a POST /v1/wait-list mediante @zot-core/sdk internamente.
  • Imprime la nueva lista de espera (_id, name, flags, marcas de tiempo).
  • Agrega ZOT_WAITLIST_ID=wl_... a .env.local.
  • Debido a que se pasó --public, también agrega NEXT_PUBLIC_ZOT_WAITLIST_ID=wl_... para uso del lado del cliente en Next.js.

Variaciones útiles:

# Pila de servidor puro (Node/Nest/Express). Omite --public.
npx @zot-core/cli waitlist create --name "Lista Beta" --write-env .env

# Uso no interactivo / mediante script. Imprime solo JSON.
npx @zot-core/cli waitlist create --name "Lista Beta" --api-key $ZOT_API_KEY --json

# Deshabilitar el correo de bienvenida automático.
npx @zot-core/cli waitlist create --name "Lista Silenciosa" --no-send-email

Si el CLI sale con No API key found, ejecuta npx @zot-core/cli login para autenticar y escribir ZOT_API_KEY en el archivo de entorno, o obtén una de https://app.zot.so/app/api-keys y expórtala en el shell / agrégala a .env.local / .env antes de reintentar.

Alternativa: crearla desde código (solo si tienes una razón clara)

import { ZotSDK } from "@zot-core/sdk";

const zot = new ZotSDK({ apiKey: process.env.ZOT_API_KEY! });

const waitlist = await zot.waitlists.create({
  name: "Acceso Anticipado",
  sendEmailToNewSignup: true,
});

console.log(waitlist._id); // <- guarda esto como ZOT_WAITLIST_ID

Solo haz esto si el usuario quiere explícitamente un flujo de creación dentro de su propia aplicación (por ejemplo, interfaz de administración que crea nuevas listas de espera por inquilino). Para una configuración única de proyecto, siempre prefiere el CLI.

Variables de entorno

Elige el patrón que coincida con el entorno de ejecución.

Servidor puro / Node / backend

# .env
ZOT_API_KEY=zot_xxx
ZOT_WAITLIST_ID=wl_abc123

Next.js con el hook React en el cliente

# .env.local
NEXT_PUBLIC_ZOT_API_KEY=zot_xxx_signup_only
NEXT_PUBLIC_ZOT_WAITLIST_ID=wl_abc123

Usa la clave NEXT_PUBLIC_ solo para la clave con ámbito de registro. Mantén la clave de acceso completo del lado del servidor bajo ZOT_API_KEY.

Patrón A - Servidor / ruta de API

Úsalo cuando el formulario se envíe a tu backend (Server Action de Next.js, ruta de API, manejador de Express, controlador de Nest, etc.).

// app/api/waitlist/route.ts (App Router de Next.js)
import { NextResponse } from "next/server";
import { ZotSDK, ZotAPIError } from "@zot-core/sdk";

const zot = new ZotSDK({ apiKey: process.env.ZOT_API_KEY! });

export async function POST(request: Request) {
  const { email, name } = await request.json();

  try {
    const user = await zot.waitlist(process.env.ZOT_WAITLIST_ID!).addUser({
      email,
      name,
    });
    return NextResponse.json({ ok: true, user });
  } catch (err) {
    if (err instanceof ZotAPIError) {
      if (err.statusCode === 409) {
        return NextResponse.json(
          { ok: false, reason: "already_registered" },
          { status: 409 },
        );
      }
      return NextResponse.json(
        { ok: false, reason: "zot_error", details: err.body },
        { status: err.statusCode },
      );
    }
    return NextResponse.json({ ok: false }, { status: 500 });
  }
}

Patrón B - Componente cliente de Next.js con useAddUser (recomendado para páginas de aterrizaje)

Esta es la forma canónica cuando el formulario vive en un componente React. El hook persiste el estado "ya registrado" en localStorage claveado por waitlistId, por lo que los visitantes recurrentes ven la confirmación sin un viaje de ida y vuelta al servidor.

En el panel de control de Zot, una lista de espera se considera "conectada" después de que el primer registro exitoso llega al endpoint de registro. Si el usuario tiene un banner de guía de conexión, debería desaparecer después de un envío exitoso real.

"use client";

import { useState } from "react";
import { useAddUser } from "@zot-core/sdk/react";

export function WaitlistForm() {
  const [email, setEmail] = useState("");
  const [name, setName] = useState("");

  const { addUser, isPending, isUserRegistered, error, reset } = useAddUser({
    apiKey: process.env.NEXT_PUBLIC_ZOT_API_KEY!,
    waitlistId: process.env.NEXT_PUBLIC_ZOT_WAITLIST_ID!,
    onSuccess: () => {
      // Opcional: analytics, toast, redirección, etc.
    },
  });

  if (isUserRegistered) {
    return (
      <div>
        <p>Estás en la lista. Te enviaremos un correo electrónico pronto.</p>
        <button type="button" onClick={reset}>
          Registrar otro correo electrónico
        </button>
      </div>
    );
  }

  return (
    <form
      onSubmit={(event) => {
        event.preventDefault();
        addUser({ email, name: name || undefined });
      }}
    >
      <input
        type="email"
        value={email}
        onChange={(event) => setEmail(event.target.value)}
        placeholder="[email protected]"
        required
        disabled={isPending}
      />
      <input
        type="text"
        value={name}
        onChange={(event) => setName(event.target.value)}
        placeholder="Tu nombre (opcional)"
        disabled={isPending}
      />
      <button type="submit" disabled={isPending}>
        {isPending ? "Uniéndose..." : "Únete a la lista de espera"}
      </button>
      {error && (
        <p role="alert">
          {"statusCode" in error && (error as { statusCode: number }).statusCode === 409
            ? "Este correo electrónico ya está en la lista."
            : error.message}
        </p>
      )}
    </form>
  );
}

Superficie completa de la API (solo lo que necesitas)

Cliente del lado del servidor

import { ZotSDK } from "@zot-core/sdk";
const zot = new ZotSDK({ apiKey: "zot_xxx" });
LlamadaPropósito
zot.waitlists.create(params)Crear una lista de espera.
zot.waitlists.list()Listar listas de espera para la clave API.
zot.waitlist(id).get()Obtener una lista de espera.
zot.waitlist(id).update(params)Actualizar configuraciones.
zot.waitlist(id).delete()Eliminar permanentemente.
zot.waitlist(id).stats()Estadísticas agregadas.
zot.waitlist(id).addUser({ email, name?, referredBy?, source?, metadata? })Registrar un usuario.
zot.waitlist(id).listUsers()Listar usuarios.
zot.waitlist(id).userCount(){ total, referred }.
zot.waitlist(id).searchUser(email)Encontrar un usuario.
zot.waitlist(id).updateUserStatus({ email, status })El estado es `"waiting"
zot.waitlist(id).bulkDeleteUsers(emails)Acepta un solo correo electrónico o un array.
zot.waitlist(id).blockedUsers() / blockedUserCount()Usuarios bloqueados.
zot.waitlist(id).webhookEvents()Historial de entrega de webhooks.

Hook React

import { useAddUser } from "@zot-core/sdk/react";

const { addUser, data, error, isPending, isUserRegistered, isError, reset } = useAddUser({
  apiKey: "...",
  waitlistId: "wl_...",
  onSuccess: (user) => {},
  onError: (err) => {},
});

Todo lo que devuelve el hook está listado arriba. No crees estado paralelo para estos valores.

Códigos de error

CódigoSignificadoGuía de UX
400Error de validaciónMuestra error a nivel de campo.
401Clave API incorrecta/faltanteNunca se muestra a los usuarios finales, regístralo.
404Lista de espera no encontradaProblema de configuración, regístralo.
409Correo electrónico ya registradoTrátalo como éxito en la mayoría de las páginas de aterrizaje.
429Límite de velocidad superadoPide al usuario que intente de nuevo en un minuto.
5xxProblema del servidorReintenta una vez, luego pide al usuario que intente más tarde.

Detéctalo con err instanceof ZotAPIError y lee err.statusCode y err.body.

Anti-patrones - NO hagas esto

  • fetch en bruto ("https://api.zot.so/v1/wait-list/..."). Usa el SDK.
  • Envolver useAddUser en useMutation de TanStack Query. Redundante.
  • Agregar un useState<boolean> manual para carga. Usa isPending.
  • Almacenar "ya registrado" en tu propia clave de localStorage. useAddUser ya lo hace bajo zot:waitlist:registered:<waitlistId>.
  • Usar la clave de acceso completo ZOT_API_KEY dentro de un componente "use client".
  • Llamar a zot.waitlists.create en cada renderizado, compilación o inicio de la aplicación. Usa npx @zot-core/cli waitlist create una vez en la configuración y almacena el ID.
  • Codificar el ID de la lista de espera dentro del componente. Léelelo de env (ZOT_WAITLIST_ID o NEXT_PUBLIC_ZOT_WAITLIST_ID).
  • Tragar errores silenciosamente. El 409 es una decisión de producto; los demás deben mostrarse o registrarse.

Lista de verificación

Antes de decirle al usuario que la integración está completa, confirma TODO lo siguiente:

  • @zot-core/sdk está en package.json en la última versión publicada.
  • Existe una lista de espera y su ID está almacenado en env (creado mediante npx @zot-core/cli waitlist create o, solo si está justificado, mediante un script de una sola vez).
  • La clave API está en las variables de entorno, no codificada.
  • Si la clave se usa en código del cliente, está prefijada con NEXT_PUBLIC_ (o equivalente) Y es una clave con ámbito de registro.
  • El ID de la lista de espera se lee de env, no está codificado, a menos que el usuario haya solicitado explícitamente una constante codificada.
  • El manejador de envío captura errores y la interfaz de usuario muestra algo para el caso de error.
  • El estado de éxito se maneja (ya sea el isUserRegistered del hook o tu propia redirección/toast después de onSuccess).
  • Al menos un registro real se probó con éxito (esto es lo que marca la lista de espera como conectada en el panel de control).
  • No hay fetch en bruto a api.zot.so en ninguna parte.
  • No hay estado duplicado de carga/error/éxito alrededor de useAddUser.

Si alguna casilla está sin marcar, arréglala antes de devolver la tarea al usuario.

Skills relacionados