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
- Use o SDK oficial. Nome do pacote:
@zot-core/sdk. Nunca chamehttps://api.zot.socomfetchpuro,axiosou similar. - 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"
- Servidor, rota de API, cron, script, função de borda ->
- Nunca embrulhe
useAddUserem TanStack Query, SWR,useState, Zustand, ou um reducer personalizado. O hook já expõeisPending,isUserRegistered,data,error,isErrorereset. Reutilizar seu estado é o objetivo. - 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). - 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:
- Chave de API - o caminho mais rápido é
npx @zot-core/cli login, que autentica o usuário e escreve uma novaZOT_API_KEYno 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. - 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/agentsapenas instala este guia de agente em um repositório;@zot-core/clise 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-listvia@zot-core/sdkinternamente. - Imprime a nova lista de espera (
_id,nome, flags, timestamps). - Adiciona
ZOT_WAITLIST_ID=wl_...a.env.local. - Como
--publicfoi passado, também adicionaNEXT_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" });
| Chamada | Propó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ódigo | Significado | Orientação de UX |
|---|---|---|
| 400 | Erro de validação | Mostre erro no nível do campo. |
| 401 | Chave de API inválida/ausente | Nunca mostre para usuários finais, registre. |
| 404 | Lista de espera não encontrada | Problema de configuração, registre. |
| 409 | E-mail já registrado | Trate como sucesso na maioria das landing pages. |
| 429 | Limite de taxa excedido | Peça ao usuário para tentar novamente em um minuto. |
| 5xx | Problema no servidor | Tente 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
fetchpuro para "https://api.zot.so/v1/wait-list/...". Use o SDK.- Embrulhar
useAddUseremuseMutationdo TanStack Query. Redundante. - Adicionar um
useState<boolean>manual para carregamento. UseisPending. - Armazenar "já registrado" em sua própria chave de localStorage.
useAddUserjá faz isso sobzot:waitlist:registered:<waitlistId>. - Usar a chave de acesso total
ZOT_API_KEYdentro de um componente"use client". - Chamar
zot.waitlists.createem toda renderização, build ou inicialização do aplicativo. Usenpx @zot-core/cli waitlist createuma vez na configuração e armazene o ID. - Codificar o ID da lista de espera dentro do componente. Leia-o do ambiente (
ZOT_WAITLIST_IDouNEXT_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/sdkestá empackage.jsonna 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 createou, 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
isUserRegistereddo hook ou seu próprio redirecionamento/toast apósonSuccess). - Pelo menos um cadastro real foi testado com sucesso (isso é o que marca a lista de espera como conectada no painel).
- Nenhum
fetchpuro paraapi.zot.soem 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.