Zot 等待清單 - 最佳實作
本技能告訴您如何正確整合 Zot 等待清單。請遵循這些規則。請勿自行發明替代方案。
快速上手 - 最短路徑
# 1. 安裝 SDK
npm install @zot-core/sdk
# 2. 建立等待清單並將其 ID 儲存在 .env.local 中
npx @zot-core/cli waitlist create --name "搶先體驗名單" --write-env .env.local --public
# 3. 使用 `@zot-core/sdk/react` 的 `useAddUser` 建立 UI(請參閱下方的模式 B)
以上就是 Next.js 專案的完整整合。請勿新增 TanStack Query,請勿撰寫自訂的 POST handler,請勿使用原始 fetch 呼叫 API。您所需的一切都在下方。
不可妥協的規則
- 使用官方 SDK。 套件名稱:
@zot-core/sdk。絕不要使用原始fetch、axios或類似工具呼叫https://api.zot.so。 - 根據程式碼執行的位置選擇正確的進入點:
- 伺服器、API 路由、定時任務、腳本、邊緣函式 ->
import { ZotSDK } from "@zot-core/sdk" - 在瀏覽器中執行的 React 元件 ->
import { useAddUser } from "@zot-core/sdk/react"
- 伺服器、API 路由、定時任務、腳本、邊緣函式 ->
- 絕不要 將
useAddUser包裝在 TanStack Query、SWR、useState、Zustand 或自訂 reducer 中。該 hook 已經公開了isPending、isUserRegistered、data、error、isError和reset。重複使用其狀態正是關鍵所在。 - 絕不要 將伺服器端的 API 金鑰傳送給客戶端。對於瀏覽器端的程式碼,請使用僅具註冊權限的金鑰,並將其以
NEXT_PUBLIC_ZOT_API_KEY(或您框架的公開環境變數等效物)暴露出來。 - 務必處理
ZotAPIError。 針對 409(已註冊)和 429(速率限制)錯誤,顯示使用者友善的說明。
安裝
npm install @zot-core/sdk
# 或
pnpm add @zot-core/sdk
# 或
yarn add @zot-core/sdk
伺服器端使用不需額外的同儕依賴。對於 hook,則需要已經安裝 react >= 18(SDK 將其標記為選用的同儕依賴)。
取得您的憑證
您需要兩項東西:
- API 金鑰 - 最快速的方法是執行
npx @zot-core/cli login,它會驗證使用者身分並將一個全新的ZOT_API_KEY寫入本機的 env 檔案。或者,您也可以從 Zot Dashboard (https://app.zot.so/app/api-keys) 手動產生一個金鑰。建立一個用於伺服器端的金鑰,如果您打算從瀏覽器端呼叫,則再建立第二個僅限註冊權限的金鑰。 - 等待清單 ID - 格式類似
wl_abc123。
# 驗證並將 ZOT_API_KEY 儲存到 .env.local(如果您傳遞 --env .env,則儲存到 .env)
npx @zot-core/cli login
使用 @zot-core/cli 建立等待清單(建議)
如果使用者還沒有等待清單,請使用官方的 Zot CLI。它會使用使用者的 ZOT_API_KEY 呼叫 Zot API,並將結果 ID 直接寫入 env 檔案,這樣您就不需要手動複製貼上。
套件:
@zot-core/cli。請勿 將其與@zot-core/agents混淆 -@zot-core/agents只會將此代理指南安裝到儲存庫中;@zot-core/cli則會與 Zot API 溝通。
# 確保 ZOT_API_KEY 已設定(在 shell、.env.local 或 .env 中)
npx @zot-core/cli waitlist create \
--name "搶先體驗名單" \
--write-env .env.local \
--public
這會做什麼:
- 透過
@zot-core/sdk在底層呼叫POST /v1/wait-list。 - 印出新的等待清單(
_id、name、旗標、時間戳記)。 - 將
ZOT_WAITLIST_ID=wl_...附加到.env.local。 - 因為傳遞了
--public,它還會將NEXT_PUBLIC_ZOT_WAITLIST_ID=wl_...附加到檔案中,以便在 Next.js 的客戶端使用。
有用的變體:
# 純伺服器端堆疊 (Node/Nest/Express)。省略 --public。
npx @zot-core/cli waitlist create --name "Beta 名單" --write-env .env
# 非互動式 / 腳本化使用。僅輸出 JSON。
npx @zot-core/cli waitlist create --name "Beta 名單" --api-key $ZOT_API_KEY --json
# 停用自動歡迎 Email。
npx @zot-core/cli waitlist create --name "安靜名單" --no-send-email
如果 CLI 因 No API key found 而結束,請執行 npx @zot-core/cli login 來驗證並將 ZOT_API_KEY 寫入 env 檔案,或者從 https://app.zot.so/app/api-keys 取得一個金鑰,並在重試之前將其匯出到 shell / 新增到 .env.local / .env。
替代方案:從程式碼建立(僅在您有明確理由時使用)
import { ZotSDK } from "@zot-core/sdk";
const zot = new ZotSDK({ apiKey: process.env.ZOT_API_KEY! });
const waitlist = await zot.waitlists.create({
name: "搶先體驗名單",
sendEmailToNewSignup: true,
});
console.log(waitlist._id); // <- 將此儲存為 ZOT_WAITLIST_ID
僅當使用者明確想在他們自己的應用程式內部建立建立流程時(例如,為每個租戶建立新等待清單的管理 UI),才這麼做。對於一次性專案設定,一律優先使用 CLI。
環境變數
選擇與執行時期相符的模式。
純伺服器端 / Node / 後端
# .env
ZOT_API_KEY=zot_xxx
ZOT_WAITLIST_ID=wl_abc123
Next.js 搭配客戶端 React hook
# .env.local
NEXT_PUBLIC_ZOT_API_KEY=zot_xxx_signup_only
NEXT_PUBLIC_ZOT_WAITLIST_ID=wl_abc123
僅將 NEXT_PUBLIC_ 金鑰用於僅限註冊權限的金鑰。將完整存取權限的金鑰保留在 ZOT_API_KEY 下的伺服器端。
模式 A - 伺服器端 / API 路由
當表單提交到您的後端時使用(Next.js Server Action、API 路由、Express handler、Nest controller 等)。
// 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 });
}
}
模式 B - 使用 useAddUser 的 Next.js 客戶端元件(建議用於登陸頁面)
這是當表單位於 React 元件中時的標準做法。該 hook 會將「已註冊」狀態以 waitlistId 為鍵儲存在 localStorage 中,因此回訪訪客無需伺服器往返即可看到確認訊息。
在 Zot Dashboard 中,等待清單在第一次成功的註冊請求到達註冊端點後被視為「已連線」。如果使用者有連線指南橫幅,它應該在真正成功的提交後消失。
"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: () => {
// 可選:分析、提示訊息、重新導向等
},
});
if (isUserRegistered) {
return (
<div>
<p>您已在名單上。我們會很快寄 Email 給您。</p>
<button type="button" onClick={reset}>
註冊另一個 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="您的姓名(選填)"
disabled={isPending}
/>
<button type="submit" disabled={isPending}>
{isPending ? "加入中..." : "加入等待清單"}
</button>
{error && (
<p role="alert">
{"statusCode" in error && (error as { statusCode: number }).statusCode === 409
? "此 Email 已在名單上。"
: error.message}
</p>
)}
</form>
);
}
完整的 API 介面(僅您需要的部分)
伺服器端客戶端
import { ZotSDK } from "@zot-core/sdk";
const zot = new ZotSDK({ apiKey: "zot_xxx" });
| 呼叫 | 用途 |
|---|---|
zot.waitlists.create(params) | 建立等待清單。 |
zot.waitlists.list() | 列出此 API 金鑰的等待清單。 |
zot.waitlist(id).get() | 取得一個等待清單。 |
zot.waitlist(id).update(params) | 更新設定。 |
zot.waitlist(id).delete() | 永久刪除。 |
zot.waitlist(id).stats() | 彙總統計資料。 |
zot.waitlist(id).addUser({ email, name?, referredBy?, source?, metadata? }) | 註冊一個使用者。 |
zot.waitlist(id).listUsers() | 列出使用者。 |
zot.waitlist(id).userCount() | { total, referred }。 |
zot.waitlist(id).searchUser(email) | 尋找使用者。 |
zot.waitlist(id).updateUserStatus({ email, status }) | 狀態為 "waiting" | "invited" | "converted" | "churned"。 |
zot.waitlist(id).bulkDeleteUsers(emails) | 接受單一 Email 或陣列。 |
zot.waitlist(id).blockedUsers() / blockedUserCount() | 被封鎖的使用者。 |
zot.waitlist(id).webhookEvents() | Webhook 傳遞記錄。 |
React hook
import { useAddUser } from "@zot-core/sdk/react";
const { addUser, data, error, isPending, isUserRegistered, isError, reset } = useAddUser({
apiKey: "...",
waitlistId: "wl_...",
onSuccess: (user) => {},
onError: (err) => {},
});
hook 回傳的所有內容都已列出。請勿為這些值建立並行的狀態。
錯誤碼
| 代碼 | 意義 | 使用者體驗指引 |
|---|---|---|
| 400 | 驗證錯誤 | 顯示欄位層級的錯誤。 |
| 401 | API 金鑰錯誤/遺失 | 絕不向終端使用者顯示,請記錄日誌。 |
| 404 | 找不到等待清單 | 設定問題,請記錄日誌。 |
| 409 | Email 已註冊 | 在大多數登陸頁面中視為成功。 |
| 429 | 超過速率限制 | 要求使用者一分鐘後再試一次。 |
| 5xx | 伺服器問題 | 重試一次,然後要求使用者稍後再試。 |
使用 err instanceof ZotAPIError 來偵測,並讀取 err.statusCode 和 err.body。
反模式 - 請勿執行這些操作
- 使用原始
fetch("https://api.zot.so/v1/wait-list/...")。請使用 SDK。 - 將
useAddUser包裝在 TanStack Query 的useMutation中。這是冗餘的。 - 為了載入狀態而新增手動的
useState<boolean>。請使用isPending。 - 將「已註冊」狀態儲存在您自己的 localStorage 鍵中。
useAddUser已經以zot:waitlist:registered:<waitlistId>為鍵處理了。 - 在
"use client"元件中使用完整存取權限的ZOT_API_KEY。 - 在每次渲染、建置或應用程式啟動時呼叫
zot.waitlists.create。請在設定時執行一次npx @zot-core/cli waitlist create並儲存 ID。 - 在元件內部將等待清單 ID 寫死。請從環境變數(
ZOT_WAITLIST_ID或NEXT_PUBLIC_ZOT_WAITLIST_ID)讀取。 - 默默吞掉錯誤。409 是一個產品決策;其他錯誤則應呈現或記錄下來。
驗證檢查清單
在告訴使用者整合完成之前,請確認所有下列項目:
-
@zot-core/sdk存在於package.json中,且為最新發行版本。 - 存在一個等待清單,且其 ID 已儲存在 env 中(透過
npx @zot-core/cli waitlist create建立,或僅在有充分理由時,透過一次性腳本建立)。 - API 金鑰存在於環境變數中,而非寫死在程式碼中。
- 如果金鑰用於客戶端程式碼,則其前綴為
NEXT_PUBLIC_(或等效物)且為僅限註冊權限的金鑰。 - 等待清單 ID 是從環境變數讀取的,而非寫死的,除非使用者明確要求一個寫死的常數。
- 提交處理程序會捕獲錯誤,且 UI 會針對錯誤情況呈現某些內容。
- 已處理成功狀態(hook 的
isUserRegistered,或是您自己在onSuccess後的重新導向/提示訊息)。 - 至少已成功測試一次真實的註冊(這會將等待清單在 Dashboard 中標記為已連線)。
- 任何地方都沒有對
api.zot.so使用原始fetch。 -
useAddUser周圍沒有重複的載入/錯誤/成功狀態。
如果有任何項目未勾選,請先修正後再將任務交回給使用者。