zot-skills

Intégrez une liste d'attente Zot dans n'importe quelle application TypeScript, React ou Next.js grâce au SDK officiel `@zot-core/sdk` et à l'outil CLI `@zot-core/cli`.

Qu'est-ce que zot-skills ?

Ce skill guide le développeur dans l'intégration d'une liste d'attente Zot, une solution de capture d'emails pour les phases early-access et les pages « coming soon », dans tout projet TypeScript, React ou Next.js. Il impose l'utilisation exclusive du SDK officiel (`@zot-core/sdk`) et de l'outil en ligne de commande (`@zot-core/cli`), en interdisant tout appel HTTP brut, l'emploi de bibliothèques de gestion d'état redondantes (TanStack Query, Zustand) et le stockage manuel de l'état d'inscription. Le skill détaille deux patrons d'intégration : un patron serveur (API routes, Server Actions) avec `ZotSDK`, et un patron client pour les composants React avec le hook `useAddUser` qui gère automatiquement le chargement, la persistance locale et la détection des doublons (code 409). Il fournit également des règles strictes de gestion des clés API (clé publique limitée aux inscriptions côté client), la gestion des erreurs via `ZotAPIError`, et une check-list de vérification pour valider l'intégration avant de la remettre à l'utilisateur.

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

Installed? Explore more Productivité et collaboration skills: steipete/gemini, steipete/gh-issues, steipete/skill-creator · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Zot Waitlist - Bonnes Pratiques

Ce skill explique comment intégrer correctement une liste d'attente Zot. Suivez ces règles. N'inventez pas d'alternatives.

TL;DR - le chemin le plus court

# 1. Installer le SDK
npm install @zot-core/sdk

# 2. Créer la liste d'attente et persister son ID dans .env.local
npx @zot-core/cli waitlist create --name "Early Access" --write-env .env.local --public

# 3. Construire l'interface utilisateur (voir Patron B ci-dessous) avec `useAddUser` depuis "@zot-core/sdk/react"

Ceci est l'intégration complète pour un projet Next.js. N'ajoutez pas TanStack Query, n'écrivez pas de gestionnaire POST personnalisé, n'appelez pas l'API avec fetch brut. Tout ce dont vous avez besoin se trouve ci-dessous.

Règles non-négociables

  1. Utilisez le SDK officiel. Nom du package : @zot-core/sdk. N'appelez jamais https://api.zot.so avec fetch, axios ou équivalent brut.
  2. Choisissez le bon point d'entrée selon l'endroit où le code s'exécute :
    • Serveur, route API, cron, script, fonction edge -> import { ZotSDK } from "@zot-core/sdk"
    • Composant React s'exécutant dans le navigateur -> import { useAddUser } from "@zot-core/sdk/react"
  3. N'enveloppez jamais useAddUser dans TanStack Query, SWR, useState, Zustand ou un reducer personnalisé. Le hook expose déjà isPending, isUserRegistered, data, error, isError et reset. Réutiliser son état est tout l'intérêt.
  4. N'expédiez jamais une clé API serveur au client. Pour le code navigateur, utilisez une clé avec les permissions d'inscription uniquement et exposez-la sous NEXT_PUBLIC_ZOT_API_KEY (ou l'équivalent public-env de votre framework).
  5. Gérez toujours ZotAPIError. Affichez un message explicite pour les codes 409 (déjà inscrit) et 429 (limite de débit).

Installer

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

Aucune dépendance supplémentaire n'est requise pour une utilisation serveur. Pour le hook, react >= 18 doit déjà être installé (le SDK le marque comme dépendance optionnelle).

Obtenir vos identifiants

Vous avez besoin de deux choses :

  1. Clé API - le chemin le plus rapide est npx @zot-core/cli login, qui authentifie l'utilisateur et écrit une nouvelle ZOT_API_KEY dans le fichier d'environnement local. Sinon, générez-en une manuellement depuis le tableau de bord Zot à https://app.zot.so/app/api-keys. Créez une clé pour le serveur et, si vous prévoyez d'appeler depuis le navigateur, une seconde clé limitée aux inscriptions.
  2. ID de la liste d'attente - ressemble à wl_abc123.
# S'authentifier et persister ZOT_API_KEY dans .env.local (ou .env si vous passez --env .env)
npx @zot-core/cli login

Créer la liste d'attente avec @zot-core/cli (recommandé)

Si l'utilisateur n'a pas déjà de liste d'attente, utilisez le CLI officiel de Zot. Il appelle l'API Zot avec la ZOT_API_KEY de l'utilisateur et écrit l'ID résultant directement dans le fichier d'environnement pour éviter tout copier-coller.

Package : @zot-core/cli. Ne le confondez pas avec @zot-core/agents - @zot-core/agents installe uniquement ce guide d'agent dans un dépôt ; @zot-core/cli communique avec l'API Zot.

# Assurez-vous que ZOT_API_KEY est définie (dans le terminal, dans .env.local ou dans .env)
npx @zot-core/cli waitlist create \
  --name "Early Access" \
  --write-env .env.local \
  --public

Ce que cela fait :

  • Appelle POST /v1/wait-list via @zot-core/sdk en coulisse.
  • Affiche la nouvelle liste d'attente (_id, name, flags, timestamps).
  • Ajoute ZOT_WAITLIST_ID=wl_... à .env.local.
  • Parce que --public a été passé, il ajoute également NEXT_PUBLIC_ZOT_WAITLIST_ID=wl_... pour une utilisation côté client dans Next.js.

Variantes utiles :

# Stack purement serveur (Node/Nest/Express). Supprimez --public.
npx @zot-core/cli waitlist create --name "Beta list" --write-env .env

# Utilisation non interactive / scriptée. Affiche uniquement du JSON.
npx @zot-core/cli waitlist create --name "Beta list" --api-key $ZOT_API_KEY --json

# Désactiver l'email de bienvenue automatique.
npx @zot-core/cli waitlist create --name "Quiet list" --no-send-email

Si le CLI se termine avec No API key found, exécutez npx @zot-core/cli login pour vous authentifier et écrire ZOT_API_KEY dans le fichier d'environnement, ou récupérez-en une depuis https://app.zot.so/app/api-keys et exportez-la dans le terminal / ajoutez-la à .env.local / .env avant de réessayer.

Alternative : créer la liste depuis le code (uniquement si vous avez une raison claire)

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

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

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

console.log(waitlist._id); // <- enregistrez cet ID comme ZOT_WAITLIST_ID

Faites ceci uniquement si l'utilisateur souhaite explicitement un flux de création dans sa propre application (par exemple, une interface d'administration qui crée de nouvelles listes d'attente par locataire). Pour une configuration de projet ponctuelle, préférez toujours le CLI.

Variables d'environnement

Choisissez le motif correspondant à l'environnement d'exécution.

Serveur pur / Node / backend

# .env
ZOT_API_KEY=zot_xxx
ZOT_WAITLIST_ID=wl_abc123

Next.js avec le hook React côté client

# .env.local
NEXT_PUBLIC_ZOT_API_KEY=zot_xxx_inscriptions_uniquement
NEXT_PUBLIC_ZOT_WAITLIST_ID=wl_abc123

Utilisez la clé NEXT_PUBLIC_ uniquement pour la clé limitée aux inscriptions. Gardez la clé avec accès complet côté serveur sous ZOT_API_KEY.

Patron A - Serveur / Route API

Utilisez ceci lorsque le formulaire est soumis à votre backend (Server Action Next.js, route API, gestionnaire Express, contrôleur 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 });
  }
}

Patron B - Composant client Next.js avec useAddUser (recommandé pour les pages d'atterrissage)

C'est la manière canonique lorsque le formulaire se trouve dans un composant React. Le hook persiste l'état "déjà inscrit" dans localStorage avec la clé waitlistId, de sorte que les visiteurs réguliers voient la confirmation sans aller-retour vers le serveur.

Dans le tableau de bord Zot, une liste d'attente est considérée comme "connectée" après que la première inscription réussie atteint le point de terminaison d'enregistrement. Si l'utilisateur a une bannière de guide de connexion, elle devrait disparaître après une soumission réussie réelle.

"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: () => {
      // Optionnel : analytics, toast, redirection, etc.
    },
  });

  if (isUserRegistered) {
    return (
      <div>
        <p>Vous êtes sur la liste. Nous vous enverrons un email bientôt.</p>
        <button type="button" onClick={reset}>
          Enregistrer un autre email
        </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="Votre nom (optionnel)"
        disabled={isPending}
      />
      <button type="submit" disabled={isPending}>
        {isPending ? "Inscription..." : "Rejoindre la liste d'attente"}
      </button>
      {error && (
        <p role="alert">
          {"statusCode" in error && (error as { statusCode: number }).statusCode === 409
            ? "Cet email est déjà sur la liste."
            : error.message}
        </p>
      )}
    </form>
  );
}

Surface API complète (uniquement ce dont vous avez besoin)

Client côté serveur

import { ZotSDK } from "@zot-core/sdk";
const zot = new ZotSDK({ apiKey: "zot_xxx" });
AppelObjectif
zot.waitlists.create(params)Créer une liste d'attente.
zot.waitlists.list()Lister les listes d'attente pour la clé API.
zot.waitlist(id).get()Récupérer une liste d'attente.
zot.waitlist(id).update(params)Mettre à jour les paramètres.
zot.waitlist(id).delete()Supprimer définitivement.
zot.waitlist(id).stats()Statistiques agrégées.
zot.waitlist(id).addUser({ email, name?, referredBy?, source?, metadata? })Enregistrer un utilisateur.
zot.waitlist(id).listUsers()Lister les utilisateurs.
zot.waitlist(id).userCount(){ total, referred }.
zot.waitlist(id).searchUser(email)Rechercher un utilisateur.
zot.waitlist(id).updateUserStatus({ email, status })Le statut est `"waiting"
zot.waitlist(id).bulkDeleteUsers(emails)Accepte un email unique ou un tableau.
zot.waitlist(id).blockedUsers() / blockedUserCount()Utilisateurs bloqués.
zot.waitlist(id).webhookEvents()Historique de livraison des 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) => {},
});

Tout ce que le hook retourne est listé ci-dessus. Ne créez pas d'état parallèle pour ces valeurs.

Codes d'erreur

CodeSignificationConseil UX
400Erreur de validationAffichez une erreur au niveau du champ.
401Clé API mauvaise/manquanteJamais affiché aux utilisateurs finaux, enregistrez-la dans les logs.
404Liste d'attente introuvableProblème de configuration, enregistrez-la dans les logs.
409Email déjà enregistréTraitez comme un succès dans la plupart des pages d'atterrissage.
429Limite de débit atteinteDemandez à l'utilisateur de réessayer dans une minute.
5xxProblème serveurRéessayez une fois, puis demandez à l'utilisateur de réessayer plus tard.

Détectez avec err instanceof ZotAPIError et lisez err.statusCode et err.body.

Anti-patrons - ne faites PAS ceci

  • Appel fetch brut vers https://api.zot.so/v1/wait-list/.... Utilisez le SDK.
  • Envelopper useAddUser dans useMutation de TanStack Query. Redondant.
  • Ajouter un useState<boolean> manuel pour le chargement. Utilisez isPending.
  • Stocker "déjà enregistré" dans votre propre clé localStorage. useAddUser le fait déjà sous zot:waitlist:registered:<waitlistId>.
  • Utiliser la clé ZOT_API_KEY avec accès complet dans un composant "use client".
  • Appeler zot.waitlists.create à chaque rendu, build ou démarrage d'application. Utilisez npx @zot-core/cli waitlist create une fois lors de la configuration et stockez l'ID.
  • Coder en dur l'ID de la liste d'attente dans le composant. Lisez-le depuis l'environnement (ZOT_WAITLIST_ID ou NEXT_PUBLIC_ZOT_WAITLIST_ID).
  • Avaler silencieusement les erreurs. Le code 409 est une décision produit ; les autres doivent être affichées ou enregistrées.

Liste de vérification

Avant de dire à l'utilisateur que l'intégration est terminée, confirmez TOUS les points suivants :

  • @zot-core/sdk est présent dans package.json à la dernière version publiée.
  • Une liste d'attente existe et son ID est stocké dans l'environnement (créé via npx @zot-core/cli waitlist create ou, uniquement si justifié, via un script unique).
  • La clé API est dans les variables d'environnement, pas codée en dur.
  • Si la clé est utilisée dans du code client, elle est préfixée par NEXT_PUBLIC_ (ou équivalent) ET est une clé limitée aux inscriptions.
  • L'ID de la liste d'attente est lu depuis l'environnement, pas codé en dur, sauf si l'utilisateur a explicitement demandé une constante codée en dur.
  • Le gestionnaire de soumission attrape les erreurs et l'interface utilisateur affiche quelque chose en cas d'erreur.
  • L'état de succès est géré (soit isUserRegistered du hook, soit votre propre redirection/toast après onSuccess).
  • Au moins une inscription réelle a été testée avec succès (c'est ce qui marque la liste d'attente comme connectée dans le tableau de bord).
  • Aucun appel fetch brut vers api.zot.so nulle part.
  • Aucun état de chargement/erreur/succès dupliqué autour de useAddUser.

Si une case n'est pas cochée, corrigez-la avant de remettre la tâche à l'utilisateur.

Skills associés