zot-waitlist-integration

Integre uma lista de espera do Zot em qualquer aplicação TypeScript, React ou Next.js usando o SDK oficial `@zot-core/sdk` e a ferramenta de linha de comando `@zot-core/cli`.

O que é zot-waitlist-integration?

Esta skill fornece as melhores práticas para integrar o serviço de lista de espera Zot em aplicações web modernas. O foco principal é o uso do SDK oficial `@zot-core/sdk` em vez de chamadas HTTP brutas, garantindo consistência e tratamento adequado de erros. Ela descreve dois padrões de integração: um para código servidor (API routes, Server Actions) usando `ZotSDK`, e outro otimizado para componentes React no navegador usando o hook `useAddUser`. A skill enfatiza regras rígidas, como nunca embrulhar `useAddUser` em outras bibliotecas de estado, nunca expor chaves de servidor no cliente e sempre tratar o erro `ZotAPIError` (especialmente os códigos 409 e 429). Também inclui um checklist de verificação para garantir que a integração seja completa e segura.

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

Installed? Explore more Produtividade e Colaboração skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

Lista de Espera Zot - Melhores Práticas

Esta skill ensina como integrar uma lista de espera do Zot corretamente. Siga estas regras. Não invente alternativas.

TL;DR - o caminho mais curto

# 1. Instale o SDK
npm install @zot-core/sdk

# 2. Crie a lista de espera e persista seu ID em .env.local
npx @zot-core/cli waitlist create --name "Acesso Antecipado" --write-env .env.local --public

# 3. Construa a interface (veja Padrão B abaixo) usando `useAddUser` de "@zot-core/sdk/react"

Esta é a integração completa para um projeto Next.js. Não adicione TanStack Query, não crie um handler POST personalizado, não chame a API com fetch puro. Tudo o que você precisa está abaixo.

Regras inegociáveis

  1. Use o SDK oficial. Nome do pacote: @zot-core/sdk. Nunca chame https://api.zot.so com fetch puro, axios ou similar.
  2. Escolha o ponto de entrada correto baseado em onde o código executa:
    • Servidor, rota de API, cron, script, função de borda -> import { ZotSDK } from "@zot-core/sdk"
    • Componente React que executa no navegador -> import { useAddUser } from "@zot-core/sdk/react"
  3. Nunca embrulhe useAddUser em TanStack Query, SWR, useState, Zustand, ou um reducer personalizado. O hook já expõe isPending, isUserRegistered, data, error, isError e reset. Reutilizar seu estado é o objetivo.
  4. Nunca envie uma chave de API do servidor para o cliente. Para código de navegador, use uma chave com permissões apenas de cadastro e exponha-a como NEXT_PUBLIC_ZOT_API_KEY (ou o equivalente de variável pública do seu framework).
  5. Sempre trate ZotAPIError. Mostre texto amigável para 409 (já registrado) e 429 (limite de taxa).

Instalação

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

Nenhuma dependência extra é necessária para uso no servidor. Para o hook, react >= 18 já deve estar instalado (o SDK o marca como dependência opcional).

Obtenha suas credenciais

Você precisa de duas coisas:

  1. Chave de API - o caminho mais rápido é npx @zot-core/cli login, que autentica o usuário e escreve uma nova ZOT_API_KEY no arquivo de ambiente local. Alternativamente, gere uma manualmente no painel do Zot em https://app.zot.so/app/api-keys. Crie uma chave para uso no servidor e, se planeja chamar do navegador, uma segunda chave com escopo apenas para cadastro.
  2. ID da lista de espera - parece com wl_abc123.
# Autentique e persista ZOT_API_KEY em .env.local (ou .env se você passar --env .env)
npx @zot-core/cli login

Crie a lista de espera com @zot-core/cli (recomendado)

Se o usuário ainda não tem uma lista de espera, use o CLI oficial do Zot. Ele chama a API do Zot com a ZOT_API_KEY do usuário e escreve o ID resultante diretamente no arquivo de ambiente, para que você nunca tenha que copiar e colar.

Pacote: @zot-core/cli. Não o confunda com @zot-core/agents – @zot-core/agents apenas instala este guia de agente em um repositório; @zot-core/cli se comunica com a API do Zot.

# Certifique-se de que ZOT_API_KEY está definida (no shell, em .env.local ou em .env)
npx @zot-core/cli waitlist create \
  --name "Acesso Antecipado" \
  --write-env .env.local \
  --public

O que isso faz:

  • Chama POST /v1/wait-list via @zot-core/sdk internamente.
  • Imprime a nova lista de espera (_id, nome, flags, timestamps).
  • Adiciona ZOT_WAITLIST_ID=wl_... a .env.local.
  • Como --public foi passado, também adiciona NEXT_PUBLIC_ZOT_WAITLIST_ID=wl_... para uso no lado do cliente no Next.js.

Variações úteis:

# Stack puramente servidor (Node/Nest/Express). Remova --public.
npx @zot-core/cli waitlist create --name "Lista Beta" --write-env .env

# Uso não interativo / por script. Imprime apenas JSON.
npx @zot-core/cli waitlist create --name "Lista Beta" --api-key $ZOT_API_KEY --json

# Desabilite o e-mail de boas-vindas automático.
npx @zot-core/cli waitlist create --name "Lista Silenciosa" --no-send-email

Se o CLI sair com Nenhuma chave de API encontrada, execute npx @zot-core/cli login para autenticar e escrever ZOT_API_KEY no arquivo de ambiente, ou obtenha uma em https://app.zot.so/app/api-keys e exporte-a no shell / adicione-a a .env.local / .env antes de tentar novamente.

Alternativa: crie a partir do código (apenas se tiver um motivo claro)

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

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

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

console.log(waitlist._id); // <- salve isso como ZOT_WAITLIST_ID

Faça isso apenas se o usuário quiser explicitamente um fluxo de criação dentro da própria aplicação (por exemplo, interface de administração que cria novas listas de espera por locatário). Para configuração de projeto único, sempre prefira o CLI.

Variáveis de ambiente

Escolha o padrão que corresponde ao ambiente de execução.

Servidor puro / Node / backend

# .env
ZOT_API_KEY=zot_xxx
ZOT_WAITLIST_ID=wl_abc123

Next.js com o hook React no cliente

# .env.local
NEXT_PUBLIC_ZOT_API_KEY=zot_xxx_somente_cadastro
NEXT_PUBLIC_ZOT_WAITLIST_ID=wl_abc123

Use a chave NEXT_PUBLIC_ apenas para a chave com escopo de cadastro. Mantenha a chave de acesso total no servidor sob ZOT_API_KEY.

Padrão A - Servidor / Rota de API

Use quando o formulário envia para seu backend (Server Action do Next.js, rota de API, handler Express, controller Nest, etc.).

// app/api/waitlist/route.ts (Next.js App Router)
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 });
  }
}

Padrão B - Componente cliente Next.js com useAddUser (recomendado para landing pages)

Esta é a forma canônica quando o formulário reside em um componente React. O hook persiste o estado "já registrado" em localStorage indexado por waitlistId, para que visitantes repetidos vejam a confirmação sem uma viagem de ida e volta ao servidor.

No painel do Zot, uma lista de espera é considerada "conectada" após o primeiro cadastro bem-sucedido atingir o endpoint de registro. Se o usuário tiver um banner de guia de conexão, ele deve desaparecer após um envio real bem-sucedido.

"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, redirecionamento, etc.
    },
  });

  if (isUserRegistered) {
    return (
      <div>
        <p>Você está na lista. Enviaremos um e-mail em breve.</p>
        <button type="button" onClick={reset}>
          Registrar outro e-mail
        </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="Seu nome (opcional)"
        disabled={isPending}
      />
      <button type="submit" disabled={isPending}>
        {isPending ? "Entrando..." : "Entrar na lista de espera"}
      </button>
      {error && (
        <p role="alert">
          {"statusCode" in error && (error as { statusCode: number }).statusCode === 409
            ? "Este e-mail já está na lista."
            : error.message}
        </p>
      )}
    </form>
  );
}

Superfície completa da API (apenas o que você precisa)

Cliente do lado servidor

import { ZotSDK } from "@zot-core/sdk";
const zot = new ZotSDK({ apiKey: "zot_xxx" });
ChamadaPropósito
zot.waitlists.create(params)Criar uma lista de espera.
zot.waitlists.list()Listar listas de espera para a chave de API.
zot.waitlist(id).get()Buscar uma lista de espera.
zot.waitlist(id).update(params)Atualizar configurações.
zot.waitlist(id).delete()Excluir permanentemente.
zot.waitlist(id).stats()Estatísticas agregadas.
zot.waitlist(id).addUser({ email, name?, referredBy?, source?, metadata? })Registrar um usuário.
zot.waitlist(id).listUsers()Listar usuários.
zot.waitlist(id).userCount(){ total, referred }.
zot.waitlist(id).searchUser(email)Encontrar um usuário.
zot.waitlist(id).updateUserStatus({ email, status })Status é "waiting" | "invited" | "converted" | "churned".
zot.waitlist(id).bulkDeleteUsers(emails)Aceita um único e-mail ou um array.
zot.waitlist(id).blockedUsers() / blockedUserCount()Usuários bloqueados.
zot.waitlist(id).webhookEvents()Histórico 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) => {},
});

Tudo o que o hook retorna está listado acima. Não crie estado paralelo para esses valores.

Códigos de erro

CódigoSignificadoOrientação de UX
400Erro de validaçãoMostre erro no nível do campo.
401Chave de API inválida/ausenteNunca mostre para usuários finais, registre.
404Lista de espera não encontradaProblema de configuração, registre.
409E-mail já registradoTrate como sucesso na maioria das landing pages.
429Limite de taxa excedidoPeça ao usuário para tentar novamente em um minuto.
5xxProblema no servidorTente novamente uma vez, depois peça ao usuário para tentar mais tarde.

Detecte com err instanceof ZotAPIError e leia err.statusCode e err.body.

Anti-padrões - NÃO faça estes

  • fetch puro para "https://api.zot.so/v1/wait-list/...". Use o SDK.
  • Embrulhar useAddUser em useMutation do TanStack Query. Redundante.
  • Adicionar um useState<boolean> manual para carregamento. Use isPending.
  • Armazenar "já registrado" em sua própria chave de localStorage. useAddUser já faz isso sob zot:waitlist:registered:<waitlistId>.
  • Usar a chave de acesso total ZOT_API_KEY dentro de um componente "use client".
  • Chamar zot.waitlists.create em toda renderização, build ou inicialização do aplicativo. Use npx @zot-core/cli waitlist create uma vez na configuração e armazene o ID.
  • Codificar o ID da lista de espera dentro do componente. Leia-o do ambiente (ZOT_WAITLIST_ID ou NEXT_PUBLIC_ZOT_WAITLIST_ID).
  • Engolir erros silenciosamente. 409 é uma decisão de produto; outros devem ser exibidos ou registrados.

Checklist de verificação

Antes de informar ao usuário que a integração está concluída, confirme TODOS os seguintes itens:

  • @zot-core/sdk está em package.json na versão publicada mais recente.
  • Uma lista de espera existe e seu ID está armazenado nas variáveis de ambiente (criado via npx @zot-core/cli waitlist create ou, apenas se justificado, via um script único).
  • A chave de API está nas variáveis de ambiente, não codificada.
  • Se a chave for usada em código do cliente, ela é prefixada com NEXT_PUBLIC_ (ou equivalente) E é uma chave com escopo de cadastro.
  • O ID da lista de espera é lido das variáveis de ambiente, não codificado, a menos que o usuário tenha pedido explicitamente uma constante codificada.
  • O handler de envio captura erros e a interface renderiza algo para o caso de erro.
  • O estado de sucesso é tratado (seja o isUserRegistered do hook ou seu próprio redirecionamento/toast após onSuccess).
  • Pelo menos um cadastro real foi testado com sucesso (isso é o que marca a lista de espera como conectada no painel).
  • Nenhum fetch puro para api.zot.so em lugar nenhum.
  • Nenhum estado de carregamento/erro/sucesso duplicado em torno de useAddUser.

Se alguma caixa estiver desmarcada, corrija-a antes de devolver a tarefa ao usuário.

Habilidades Relacionadas