Private surface
envie.private.* — the full server-side API: shop state, lists, analytics, transfers, webhooks, keys, and settings.
Everything under envie.private.* needs a private-mode client; in a browser these methods throw before any request is sent.
import { createEnvie } from "@getenvie/client";
const envie = createEnvie({
mode: "private",
shop: "your-store.myshopify.com",
secretKey: process.env.ENVIE_SECRET_KEY!, // Envie → Developers, shown once
});Shop & settings
const shop = await envie.private.shop();
shop.plan; // "FREE" | "GROWTH" | "PLUS"
shop.usage; // { lists, items } — live counters
shop.settings; // guestEnabled, shareEnabled, …
const embed = await envie.private.embedStatus();
embed.status; // "enabled" | "disabled" | "unsupported" | "unknown"
await envie.private.updateSettings({ shareEnabled: false });updateSettings is a patch — send only what you change. klaviyoKey is write-only (never
returned; null disconnects).
Lists
// Browse, newest first, cursor-paginated (limit ≤ 100):
const page = await envie.private.lists({ limit: 50 });
page.data; // list summaries (no items)
page.pageInfo.nextCursor; // pass back as { cursor } — null when done
// Per customer, or one list in full:
const theirs = await envie.private.lists({ customerId: "6301397778619" });
const full = await envie.private.list("lst_cmef8lmao0001"); // items includedAnalytics
const top = await envie.private.topProducts("30d"); // "7d" | "30d" | "90d"
top.data; // [{ productId, handle, titleSnapshot, saves }] — most-wishlisted first
const activity = await envie.private.activity("7d");
activity.data; // [{ date, added, removed }] — one entry per dayThe same numbers the merchant's dashboard shows — build your own reporting on top.
Exports & imports
Async jobs: create → poll → download from a signed URL (valid 24 h).
const { jobId } = await envie.private.createExport("csv"); // or "json"
let job = await envie.private.export(jobId);
while (job.status === "queued" || job.status === "running") {
await new Promise((resolve) => setTimeout(resolve, 2000));
job = await envie.private.export(jobId);
}
job.resultUrl; // signed download link — job.error explains a "failed"
const history = await envie.private.exports(); // past jobs, paginatedImports mirror the shape — upload target first, then the job (full flow, formats and skip rules in the import guide):
const { uploadUrl, fileUrl } = await envie.private.createUploadTarget({
filename: "swym-export.csv",
contentType: "text/csv",
});
await fetch(uploadUrl, { method: "PUT", body: file }); // straight to storage, 15-min window
const dryRun = await envie.private.createImport({ source: "swym", fileUrl, dryRun: true });
// review the report via import(dryRun.jobId), then re-run with dryRun: false
const status = await envie.private.import(dryRun.jobId);Webhooks
const created = await envie.private.createWebhook({
url: "https://example.com/hooks/envie",
events: ["item.added", "item.removed", "list.merged", "list.shared"],
});
created.secret; // signing secret — shown once, store it now
await envie.private.testWebhook(created.id); // signed ping through the real pipeline
const all = await envie.private.webhooks();
await envie.private.deleteWebhook(created.id);Envelope format, signature verification and retry behavior: webhooks guide.
API keys
const key = await envie.private.createKey("reporting service");
key.secret; // env_sk_… — shown once, never retrievable
const keys = await envie.private.keys(); // metadata only, never secrets
await envie.private.revokeKey(keys[0].id); // effective within a minuteOne key per service: rotation stays surgical, and lastUsedAt tells you what's actually in use.
Common mistakes
- Polling jobs or analytics in tight loops. 600 requests/minute per key; a 2-second poll interval is plenty for transfer jobs.
- Storing
createKey/createWebhooksecrets "later". Both are shown exactly once. Capture them in the same breath that creates them. - Rebuilding the dashboard from
lists()at scale. For "what changed", subscribe via webhooks; for aggregates, use the analytics endpoints — browsing every list is the slow, rate-limited way to both.