self-hosted-funnel-launch
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSelf-Hosted Funnel Launch
自托管式漏斗启动
Take a funnel from nothing to published on infrastructure the operator controls, using Autonnel (Apache-2.0). This skill is the build step; design the funnel first with , and confirm self-hosting is the right call with if that is still open.
sales-funnel-blueprintfunnel-platform-picker使用Autonnel(Apache-2.0许可证),在运营者可控的基础设施上完成漏斗从无到有的发布流程。本技能为构建步骤;请先使用设计漏斗,若仍未确定方案,可通过确认自托管是否为合适选择。
sales-funnel-blueprintfunnel-platform-pickerStep 1: choose how it runs
步骤1:选择运行方式
| Path | Cost at low volume | Ops burden | Use it for |
|---|---|---|---|
| Cloudflare Workers | Effectively $0 plus a Postgres | No servers, no patching | Default for production. Funnel pages are mostly static assets, which Workers serves free and unmetered |
| Docker | Cost of one VPS or container host | Yours: upgrades, backups, uptime | Local evaluation in two minutes, or a server you already run and want the data on |
| Source checkout (Node) | Cost of one VPS or container host | Yours | Modifying Autonnel itself, or running the Node build directly |
Recommend Workers unless the operator has a specific reason not to: the pricing model fits funnels almost exactly, and it removes the entire class of work that makes people avoid self-hosting.
Use Docker for the first look regardless. It is the fastest way to see the product, and nothing you build locally is wasted: the same schema and the same admin UI back both paths.
| 路径 | 低流量成本 | 运维负担 | 使用场景 |
|---|---|---|---|
| Cloudflare Workers | 实际成本接近0,仅需额外支付Postgres费用 | 无需服务器,无需补丁 | 生产环境默认选择。漏斗页面多为静态资源,Workers可免费无限量提供服务 |
| Docker | 一台VPS或容器主机的成本 | 需自行负责:升级、备份、可用性 | 两分钟内完成本地评估,或部署至已有服务器并保留数据 |
| 源码检出(Node) | 一台VPS或容器主机的成本 | 需自行负责 | 修改Autonnel本身,或直接运行Node构建版本 |
除非运营者有特定理由,否则推荐使用Workers:其定价模型完全适配漏斗场景,且消除了人们回避自托管的所有运维工作。
无论最终选择哪种路径,首次试用建议使用Docker。这是最快体验产品的方式,且本地构建的内容不会浪费:两种路径使用相同的数据库 schema 和管理UI。
Step 2a: Cloudflare Workers (the near-free production path)
步骤2a:Cloudflare Workers(近乎免费的生产路径)
Why the cost is close to zero
成本接近0的原因
Funnel traffic is overwhelmingly requests for pages, images and scripts. On Workers those are static asset requests, which are free and unlimited, with no storage cost - only requests that invoke the Worker (server-rendered pages, checkout, API) are billed. A funnel's dynamic surface is small: the order form, the upsell accept, the postback queue.
Verified Cloudflare free-plan limits (checked 2026-08; confirm current numbers before you rely on them):
| Resource | Workers Free plan |
|---|---|
| Static asset requests | Free and unlimited, no storage charge |
| Worker invocations | 100,000 requests/day |
| Hyperdrive (Postgres pooling) | Available on Free, 100,000 database queries/day |
| Workers KV (page cache) | 100,000 reads/day, 1,000 writes/day, 1 GB storage |
| Cron Triggers | Supported (the repo ships a |
What is not free: Postgres. Hyperdrive pools connections to a database you supply, so you still need a Postgres provider. Managed providers have their own free tiers with their own limits, and that is the one line item to plan for.
The first ceiling you will actually hit is KV writes, not requests. 1,000 writes/day is generous for serving pages and thin for publishing them, because publishing invalidates and refreshes cached entries. A day of heavy editing can burn it while traffic is nowhere near any limit. If publishing starts failing before traffic does, that is this limit, not a bug.
漏斗流量绝大多数为页面、图片和脚本请求。在Workers上,这些属于静态资源请求,免费且无限制,无存储成本——仅触发Worker的请求(服务端渲染页面、结账、API)会产生费用。漏斗的动态交互面很小:订单表单、追加销售确认、回传队列。
已验证的Cloudflare免费计划限制(2026年8月核实;使用前请确认当前最新数值):
| 资源 | Workers免费计划 |
|---|---|
| 静态资源请求 | 免费无限量,无存储费用 |
| Worker调用 | 每日100,000次请求 |
| Hyperdrive(Postgres连接池) | 免费可用,每日100,000次数据库查询 |
| Workers KV(页面缓存) | 每日100,000次读取,每日1,000次写入,1GB存储 |
| Cron触发器 | 支持(仓库提供了 |
非免费项:Postgres。Hyperdrive连接到您提供的数据库,因此您仍需Postgres服务商。托管服务商均有各自的免费层及限制,这是唯一需要规划的成本项。
实际会遇到的第一个瓶颈是KV写入次数,而非请求次数。每日1,000次写入对于页面服务来说足够,但对于发布操作则较为紧张,因为发布会失效并刷新缓存条目。大量编辑的一天可能会耗尽该限额,而此时流量远未达到任何其他限制。如果发布在流量未达限制前就开始失败,那就是这个限额导致的,而非Bug。
Deploy
部署
The repository ships the whole Workers toolchain: worker entry with the cron handler (), generation, KV cache wiring and Hyperdrive for Postgres.
scheduledsrc/cf-worker.tswrangler.tomlbash
npx wrangler login
npx wrangler kv namespace create CACHE_KV
npx wrangler hyperdrive create autonnel-db --connection-string="postgresql://user:pass@host:5432/autonnel"Each command prints an id. Put them in next to the project:
.envbash
CF_WORKER_NAME=my-funnels
CF_KV_NAMESPACE_ID=<id from kv namespace create>
CF_HYPERDRIVE_CONFIG_ID=<id from hyperdrive create>Then set the secrets and deploy:
bash
npx wrangler secret put DATABASE_URL
npx wrangler secret put AUTH_SESSION_SECRET # openssl rand -hex 32
npx wrangler secret put CREDENTIALS_ENCRYPTION_KEY # openssl rand -base64 32
npm run deploy:cfdeploy:cfwrangler.tomlwrangler.tomlIf a variable is missing, generation fails and names the variable. That is the intended behaviour; there are no silent defaults for these.
CF_*Apply the database schema once against the same Postgres before the first visit, then open the Worker URL and complete the wizard to create the admin account.
/setupAlso available: (dev server on the Workers runtime) and (local preview via ). Prefer these over plain when the target is Workers, because the runtime differs.
npm run dev:cfnpm run preview:cfwrangler devastro dev仓库提供了完整的Workers工具链:包含Cron 处理器的Worker入口()、生成、KV缓存配置和用于Postgres的Hyperdrive。
scheduledsrc/cf-worker.tswrangler.tomlbash
npx wrangler login
npx wrangler kv namespace create CACHE_KV
npx wrangler hyperdrive create autonnel-db --connection-string="postgresql://user:pass@host:5432/autonnel"每个命令都会输出一个ID。将这些ID放入项目旁的文件中:
.envbash
CF_WORKER_NAME=my-funnels
CF_KV_NAMESPACE_ID=<kv namespace create输出的ID>
CF_HYPERDRIVE_CONFIG_ID=<hyperdrive create输出的ID>然后设置密钥并部署:
bash
npx wrangler secret put DATABASE_URL
npx wrangler secret put AUTH_SESSION_SECRET # openssl rand -hex 32
npx wrangler secret put CREDENTIALS_ENCRYPTION_KEY # openssl rand -base64 32
npm run deploy:cfdeploy:cfwrangler.tomlwrangler.toml如果缺少任何变量,生成过程会失败并提示缺失的变量名。这是预期行为;这些变量没有静默默认值。
CF_*首次访问前,先对同一个Postgres应用数据库schema,然后打开Worker URL并完成向导以创建管理员账户。
/setup还提供:(Workers运行时上的开发服务器)和(通过进行本地预览)。当目标环境为Workers时,优先使用这些命令而非普通的,因为运行时存在差异。
npm run dev:cfnpm run preview:cfwrangler devastro devOperating it afterwards
后续运维
The CLI commands below need database access, not a container. From a checkout with pointing at the same Postgres:
DATABASE_URLbash
npx autonnel admin:create you@example.com 'a-strong-password'
npx autonnel password:reset you@example.com以下CLI命令需要数据库访问,无需容器。在检出的代码中,将指向同一个Postgres:
DATABASE_URLbash
npx autonnel admin:create you@example.com 'a-strong-password'
npx autonnel password:reset you@example.comStep 2b: Docker (local evaluation, or your own server)
步骤2b:Docker(本地评估或自有服务器)
bash
curl -O https://raw.githubusercontent.com/autonnel/autonnel/master/docker-compose.yml
docker compose upOpen http://localhost:4321 and complete . The compose file starts Postgres, applies the schema, and runs the app. Nothing else is needed to boot: store, payments, media storage, email and AI are configured later in the admin UI, and only for the features actually used.
/setupBefore exposing it on a public host, put real secrets in a next to - the shipped defaults are insecure development values, and they exist only so the first local run needs zero configuration:
.envdocker-compose.ymlbash
AUTH_SESSION_SECRET=$(openssl rand -hex 32)
CREDENTIALS_ENCRYPTION_KEY=$(openssl rand -base64 32)
ADMIN_DOMAIN=admin.example.comGenerate each value once and keep it stable. Rotating invalidates sessions; rotating makes stored provider credentials unreadable, which means re-entering every payment and platform credential.
AUTH_SESSION_SECRETCREDENTIALS_ENCRYPTION_KEYMulti-arch images are published to GHCR for a plain against an existing database:
docker runbash
docker run -p 4321:4321 \
-e DATABASE_URL="postgresql://user:pass@host:5432/autonnel" \
-e ADMIN_DOMAIN="admin.example.com" \
-e AUTH_SESSION_SECRET="$(openssl rand -hex 32)" \
-e CREDENTIALS_ENCRYPTION_KEY="$(openssl rand -base64 32)" \
ghcr.io/autonnel/autonnel:latestPin an exact tag in production rather than , and re-apply the schema after pulling a newer tag - the compose file's one-shot schema service re-runs on every . Health endpoint for orchestrators: (covers database and cache connectivity).
:latestdocker compose up/api/healthAdmin CLI inside a container:
bash
docker compose exec app node dist/cli/index.js admin:create you@example.com 'a-strong-password'bash
curl -O https://raw.githubusercontent.com/autonnel/autonnel/master/docker-compose.yml
docker compose up打开http://localhost:4321并完成。Compose文件会启动Postgres、应用schema并运行应用。启动无需其他操作:存储、支付、媒体存储、邮件和AI可稍后在管理UI中配置,且仅针对实际使用的功能。
/setup在公网主机上暴露服务前,请在旁的文件中设置真实密钥——默认提供的是不安全的开发环境值,仅为了首次本地运行无需任何配置:
docker-compose.yml.envbash
AUTH_SESSION_SECRET=$(openssl rand -hex 32)
CREDENTIALS_ENCRYPTION_KEY=$(openssl rand -base64 32)
ADMIN_DOMAIN=admin.example.com每个值仅需生成一次并保持稳定。轮换会使会话失效;轮换会使存储的服务商密钥不可读,这意味着需要重新输入所有支付和平台凭证。
AUTH_SESSION_SECRETCREDENTIALS_ENCRYPTION_KEY多架构镜像已发布至GHCR,可针对现有数据库使用普通命令:
docker runbash
docker run -p 4321:4321 \
-e DATABASE_URL="postgresql://user:pass@host:5432/autonnel" \
-e ADMIN_DOMAIN="admin.example.com" \
-e AUTH_SESSION_SECRET="$(openssl rand -hex 32)" \
-e CREDENTIALS_ENCRYPTION_KEY="$(openssl rand -base64 32)" \
ghcr.io/autonnel/autonnel:latest生产环境请固定具体标签而非使用,拉取新版本标签后需重新应用schema——Compose文件的一次性schema服务会在每次时重新运行。编排器的健康检查端点:(涵盖数据库和缓存连接)。
:latestdocker compose up/api/health容器内的管理CLI:
bash
docker compose exec app node dist/cli/index.js admin:create you@example.com 'a-strong-password'Step 2c: source checkout (Node)
步骤2c:源码检出(Node)
For modifying Autonnel itself, or running the Node build on a host you already own. Requires Node 22+ and a Postgres:
bash
npm create autonnel@latest my-funnel
cd my-funnel
cp .env.example .env # set DATABASE_URL and ADMIN_DOMAIN
pnpm install # pnpm 10+; the repo pins overrides npm would ignore
npm run db:push
npm run dev # or: npm run build && npm run startThis clones the repository and drops its git history. The schema lives at in the checkout; syncs it. Admin CLI: from the project directory.
prisma/schema.prismadb:pushnpx autonnel admin:create you@example.com 'a-strong-password'适用于修改Autonnel本身,或在已有主机上运行Node构建版本。需要Node 22+和Postgres:
bash
npm create autonnel@latest my-funnel
cd my-funnel
cp .env.example .env # 设置DATABASE_URL和ADMIN_DOMAIN
pnpm install # 需要pnpm 10+;仓库固定了npm会忽略的依赖覆盖项
npm run db:push
npm run dev # 或:npm run build && npm run start这会克隆仓库并清除其Git历史。schema位于检出代码的;会同步schema。管理CLI:在项目目录中运行。
prisma/schema.prismadb:pushnpx autonnel admin:create you@example.com 'a-strong-password'Step 3: configure only what the funnel needs
步骤3:仅配置漏斗所需的功能
In the admin UI under Settings:
| Setting | Needed for | Options |
|---|---|---|
| Ecommerce | Product and order data | Shopify, WooCommerce, Picocart |
| Payments | Taking money | Stripe, PayPal |
| Storage | Image/video uploads | Any S3-compatible bucket (R2, S3, MinIO) |
| Receipts, recall campaigns | SMTP, Resend, AWS SES | |
| LLM | AI page generation | Any OpenAI-compatible endpoint |
| Ad platforms | Server-side conversions | Facebook, TikTok, Google Ads, Bing |
Order of operations that avoids rework: catalog first (it constrains what the checkout can sell), then payments, then storage, then email, then ad platforms last - tracking is verified against real orders, so it needs the rest working first.
On Workers, R2 is the obvious storage choice: it is S3-compatible and keeps media egress inside Cloudflare.
在管理UI的设置中:
| 设置项 | 用途 | 可选方案 |
|---|---|---|
| 电商 | 产品和订单数据 | Shopify、WooCommerce、Picocart |
| 支付 | 收款 | Stripe、PayPal |
| 存储 | 图片/视频上传 | 任何兼容S3的存储桶(R2、S3、MinIO) |
| 邮件 | 收据、召回营销 | SMTP、Resend、AWS SES |
| LLM | AI页面生成 | 任何兼容OpenAI的端点 |
| 广告平台 | 服务端转化跟踪 | Facebook、TikTok、Google Ads、Bing |
避免返工的操作顺序:先配置商品目录(它会约束结账页可售卖的内容),然后是支付,接着是存储,再是邮件,最后是广告平台——跟踪需要基于真实订单验证,因此需要其他功能先正常工作。
在Workers上,R2是显而易见的存储选择:它兼容S3,且媒体流量可在Cloudflare内部流转。
Step 4: build the pages
步骤4:构建页面
Funnel roles map onto the funnel spec directly:
| Role in funnel | Purpose | Multiple per funnel? |
|---|---|---|
| Entry page(s), one per traffic angle | Yes |
| Order form | No - one per funnel |
| Post-purchase offers, ordered into a chain | Yes |
| Confirmation | No |
| Payment failure / fallback | No |
These are the roles a page takes inside a funnel. Over the API a page's own type is - landing pages are created as and become landing pages by being bound into a funnel as .
CHECKOUT | THANKYOU | ERROR | UPSELL | CUSTOMCUSTOMLANDINGTwo editors are available: a component-based visual editor whose output is diffable JSON, and raw HTML for imported pages. Prefer the component editor for anything that will be A/B tested or edited by an agent later - JSON diffs review cleanly, HTML blobs do not.
Build the checkout before the landing page. The checkout determines what can actually be sold and at what price, and a landing page written first will promise something the checkout cannot deliver.
漏斗角色与漏斗规范直接对应:
| 漏斗中的角色 | 用途 | 每个漏斗可包含多个? |
|---|---|---|
| 入口页面,每个流量渠道对应一个 | 是 |
| 订单表单 | 否——每个漏斗一个 |
| 售后优惠,按顺序组成链条 | 是 |
| 确认页 | 否 |
| 支付失败/回退页 | 否 |
这些是页面在漏斗中的角色。通过API创建时,页面自身的类型为——着陆页创建为类型,通过绑定到漏斗并设置为角色成为着陆页。
CHECKOUT | THANKYOU | ERROR | UPSELL | CUSTOMCUSTOMLANDING提供两种编辑器:基于组件的可视化编辑器,输出可对比差异的JSON;以及用于导入页面的原始HTML。对于需要A/B测试或后续由Agent编辑的内容,优先使用组件编辑器——JSON差异易于审核,而HTML blob则不然。
先构建结账页,再构建着陆页。结账页决定了实际可售卖的商品及价格,若先写着陆页可能会承诺结账页无法实现的功能。
Step 5: wire the funnel
步骤5:配置漏斗
- Create the funnel, then attach pages with their role and order.
- A page can belong to only one funnel. Attempting to reuse one across funnels is rejected - clone it instead.
LANDING - and
THANKYOUare auto-bound from existing pages at creation if any exist; if the tenant has none, create them before going live. A funnel with no error page fails silently on declined payments.ERROR - The funnel's promotional URL (the first landing page) is what goes into ad campaigns. Steps are reachable by short slugs so the buyer's path across steps survives cross-domain hops.
- Publish is explicit and versioned per page and per funnel - publishing a page does not publish the funnel binding.
- 创建漏斗,然后附加页面并指定其角色和顺序。
- 一个页面只能属于一个漏斗。尝试跨漏斗复用会被拒绝——请克隆页面。
LANDING - 创建漏斗时,若已有和
THANKYOU页面,会自动绑定;若租户没有这些页面,请在上线前创建。没有错误页的漏斗在支付失败时会静默出错。ERROR - 漏斗的推广URL(第一个着陆页)用于广告投放。各步骤可通过短slug访问,因此买家的跨步骤路径可跨域保持。
- 发布操作是显式的,且每个页面和漏斗都有版本控制——发布页面不会发布漏斗绑定关系。
Step 6: instrument before sending traffic
步骤6:引流前配置监控
Non-negotiable pre-launch checks:
- One real end-to-end purchase, on a real payment provider, including: base order, one accepted upsell, one declined upsell, the thank-you page, the receipt email, and the order appearing in the connected store.
- One refund on that order, to confirm the refund path works per charge.
- Click id coverage - confirm /
fbclid/ttclid/gclidreach the order record. Seemsclkid.server-side-conversion-tracking - Server-side conversion arriving in each ad platform's event debugger, with the click id attached and no duplicate against the browser event.
- Error page reachable by forcing a declined card.
On Workers, add one more: confirm the cron handler is firing (queued postbacks and recall campaigns depend on it). A deploy that silently lost its cron triggers looks healthy while background work quietly stops.
scheduledOnly then increase spend. A funnel that has not had a real transaction pushed through it has an unknown, not a low, failure rate.
上线前必须完成的检查:
- 一次完整的真实购买流程,使用真实支付服务商,包括:基础订单、一次接受的追加销售、一次拒绝的追加销售、感谢页、收据邮件,以及订单出现在关联的商店中。
- 一次退款操作,确认针对该订单的退款流程正常。
- 点击ID覆盖——确认/
fbclid/ttclid/gclid被记录到订单中。详见msclkid。server-side-conversion-tracking - 服务端转化数据到达每个广告平台的事件调试器,附带点击ID且不会与浏览器事件重复。
- 错误页可访问——通过使用无效卡片触发支付失败来验证。
在Workers上,需额外检查:确认Cron 处理器在运行(排队的回传和召回营销依赖它)。如果部署时静默丢失了Cron触发器,系统看起来正常但后台工作会悄悄停止。
scheduled完成以上检查后再增加投放预算。未经过真实交易测试的漏斗,其失败率是未知的,而非低失败率。
Step 7: operate it from an agent over MCP
步骤7:通过MCP由Agent运维
The instance exposes its admin API as MCP tools at , so an agent can build and change funnels without the UI.
/api/mcpjson
{
"mcpServers": {
"autonnel": {
"transport": "http",
"url": "https://<your-autonnel-host>/api/mcp",
"headers": { "Authorization": "Bearer <your-api-key>" }
}
}
}.mcp.jsonclaude_desktop_config.jsonwriteAccessTools are self-describing - the client reads names, descriptions and input schemas on connect, so this skill does not repeat them. What follows is only what introspection cannot tell you.
实例在暴露管理API作为MCP工具,因此Agent无需UI即可构建和修改漏斗。
/api/mcpjson
{
"mcpServers": {
"autonnel": {
"transport": "http",
"url": "https://<your-autonnel-host>/api/mcp",
"headers": { "Authorization": "Bearer <your-api-key>" }
}
}
}Claude Code使用项目根目录的;Claude Desktop使用。在管理后台→设置→API密钥生成密钥。每个调用都限定在该密钥对应的租户范围内。只读工具可使用任何密钥;修改工具需要开启。将写入密钥视为生产凭证:每个Agent一个,只读密钥用于报表,应撤销而非共享。
.mcp.jsonclaude_desktop_config.jsonwriteAccess工具是自描述的——客户端在连接时会读取名称、描述和输入schema,因此本技能不再重复这些内容。以下仅介绍 introspection 无法告知的信息。
A failed call still returns HTTP 200
失败的调用仍返回HTTP 200
This is the single thing most likely to make a client read a failure as a success.
| Condition | What you actually get |
|---|---|
| Auth failure | HTTP 401, no JSON-RPC frame at all |
| Unknown tool name | HTTP 200 with a real JSON-RPC |
| Everything else: missing write access, validation failure, not found, conflict, server error | HTTP 200 with |
So: if is present it is an unknown tool; otherwise check before trusting . Read the message rather than retrying blindly - a validation failure names the exact field path, and a conflict names the rule that was hit.
errorresult.isErrorresult.content这是最可能导致客户端将失败误认为成功的情况。
| 情况 | 实际返回内容 |
|---|---|
| 认证失败 | HTTP 401,无JSON-RPC帧 |
| 未知工具名称 | HTTP 200,返回真实的JSON-RPC |
| 其他所有情况:缺少写入权限、验证失败、未找到、冲突、服务器错误 | HTTP 200,返回 |
因此:如果存在则为未知工具;否则需先检查再信任。请阅读消息而非盲目重试——验证失败会指明确切的字段路径,冲突会指明违反的规则。
errorresult.isErrorresult.contentRules that cause most failed writes
最常导致写入失败的规则
- A funnel step is and nothing else. Order is array order. A step's role in the flow is the referenced page's own
{ stepSlug, pageId }; there is notype,pageTypeororderfield.subOrderis required onstepSlug, must be unique within the funnel, and formsadd_funnel_page. The schemas are/n/{funnelId}/{stepSlug}, so an extra field is rejected rather than ignored..strict() - Steps are keyed by the page they reference, so a page appears at most once per funnel, but the same page may be referenced by several funnels. There is no "belongs to one funnel only" rule.
- There is no page type. Page
LANDINGistype, stored uppercase. A landing page is aCHECKOUT | THANKYOU | UPSELL | ERROR | CUSTOMpage that a funnel references.CUSTOM - Thank-you and error steps are live references, not snapshots. adds steps for the tenant's existing thank-you and error pages, creating them from templates if none exist. Editing that page later changes every funnel referencing it - clone it if one funnel should diverge.
create_funnel - Draft and published are separate. Writes land in ;
draftDatapromotes it and invalidates the render cache. Write, verify withpublish: true, publish in a second call.get_page - is not structurally validated. Nothing checks
draftData/root/content, required props, or component type names before saving. A malformed document is accepted and only breaks at render time.zones - Component types must come from , never from a remembered list. The component set is renamed and extended over releases, and because
get_template({ key })is unvalidated, a stale component name saves cleanly and renders blank. A template's JSON is the authoritative shape.draftData - and
draftDataare not checked against the page'shtmlContent.editorTypeaccepts onlycreate_page;draftDataaccepts both on any page and writes whichever you send to a column the other renderer never reads. Match the field to the page's real editor type yourself.update_page - Media before pages. fetches a URL server-side and returns a CDN URL for component props. Binary upload is REST-only, not an MCP tool.
upload_media - counts unique users, not views. Five visits by one visitor is 1.
get_stats - cannot filter by funnel, and its amounts divide minor units by 100 - correct for USD/EUR, wrong for JPY or BHD.
list_orders - Ad spend is not available here. Core ads support is token-mode conversion postback only: no campaign or spend queries. Pull spend from the ad platform directly for ROAS.
- 漏斗步骤仅包含。顺序由数组顺序决定。步骤在流程中的角色由引用页面自身的
{ stepSlug, pageId }决定;不存在type、pageType或order字段。subOrder在stepSlug中是必填项,且在漏斗内必须唯一,构成路径add_funnel_page。schema是/n/{funnelId}/{stepSlug},因此多余字段会被拒绝而非忽略。.strict() - 步骤以引用的页面为键,因此一个页面在每个漏斗中最多出现一次,但同一页面可被多个漏斗引用。不存在“仅属于一个漏斗”的规则。
- 没有页面类型。页面
LANDING为type,存储为大写。着陆页是被漏斗引用的CHECKOUT | THANKYOU | UPSELL | ERROR | CUSTOM页面。CUSTOM - 感谢页和错误页是实时引用,而非快照。会为租户现有的感谢页和错误页添加步骤,若不存在则从模板创建。后续编辑该页面会修改所有引用它的漏斗——如果需要某个漏斗使用不同的页面,请克隆它。
create_funnel - 草稿和发布版本是分离的。写入内容会存入;
draftData会将其升级为发布版本并失效渲染缓存。先写入,用publish: true验证,再通过第二次调用发布。get_page - 不进行结构验证。保存前不会检查
draftData/root/content、必填属性或组件类型名称。格式错误的文档会被接受,仅在渲染时出错。zones - 组件类型必须来自,绝不能来自记忆的列表。组件集在版本迭代中会重命名和扩展,且由于
get_template({ key })未验证,过时的组件名称会被正常保存但渲染为空。模板的JSON是权威格式。draftData - 和
draftData不会与页面的htmlContent校验。editorType仅接受create_page;draftData在任何页面上都接受两者,并将您发送的内容写入另一个渲染器永远不会读取的列。请自行确保字段与页面实际的编辑器类型匹配。update_page - 先上传媒体,再创建页面。会从服务端获取URL并返回CDN URL用于组件属性。二进制上传仅支持REST,不支持MCP工具。
upload_media - 统计唯一用户数,而非浏览量。同一访客访问5次计为1次。
get_stats - 无法按漏斗过滤,且金额会将最小单位除以100——对USD/EUR正确,但对JPY或BHD错误。
list_orders - 广告支出数据无法在此获取。核心广告支持仅为令牌模式的转化回传:无广告活动或支出查询。如需计算ROAS,请直接从广告平台拉取支出数据。
Build order
构建顺序
list_products → list_templates → get_template → upload_media
→ create_page × N → get_page → edit draftData → update_page → get_page → update_page({ publish: true })
→ create_funnel → add_funnel_page × N (pageId + unique stepSlug) → get_funnelDo not treat as the URL to advertise. It is literally , and appends the thank-you and error steps before you add anything, so on a funnel built this way is the thank-you page. Read the array from , pick the step whose is , and fetch to confirm the landing page renders before spending money on it.
entryStepSlugsteps[0]create_funnelsteps[0]stepsget_funnelpage.typeCUSTOM/n/{funnelId}/{thatStepSlug}To change a live page: → edit only the props you mean to change → without publish → to diff → publish. Never regenerate a whole blob for one headline; replaces the document wholesale, and component JSON carries prop values you did not write and cannot reconstruct.
get_pageupdate_pageget_pagedraftDataupdate_pagelist_products → list_templates → get_template → upload_media
→ create_page × N → get_page → edit draftData → update_page → get_page → update_page({ publish: true })
→ create_funnel → add_funnel_page × N (pageId + 唯一stepSlug) → get_funnel请勿将作为推广URL。它实际上是,而会在您添加任何步骤前先追加感谢页和错误页,因此通过这种方式构建的漏斗,是感谢页。从读取数组,选择为的步骤,访问确认着陆页可正常渲染后再投放广告。
entryStepSlugsteps[0]create_funnelsteps[0]get_funnelstepspage.typeCUSTOM/n/{funnelId}/{thatStepSlug}修改已上线页面的流程: → 仅编辑您想要修改的属性 → 不带publish参数调用 → 对比差异 → 发布。切勿为修改一个标题而重新生成整个 blob;会完全替换文档,且组件JSON包含您未编写且无法重构的属性值。
get_pageupdate_pageget_pagedraftDataupdate_pageREST is not the same surface
REST与MCP界面不同
Thirteen tools are also reachable over REST through a bridge that runs the identical schema and handler, so those cannot drift. Seven are MCP-only: , , , , , , . Some of those have an older, independently written REST endpoint at the same path with a different response shape or parameter name ( takes , not ). Do not assume a REST endpoint matches the tool of the same name.
list_funnelsget_funnellist_pagesget_pagelist_productsdeliver_orderget_statsGET /productsqsearchOne path trap: lists email templates for Settings, not Puck page templates. Page templates are at .
/api/v1.1/templates/api/v1.1/page-templates13个工具也可通过REST访问,通过桥接器运行相同的schema和处理器,因此不会出现差异。7个工具仅支持MCP:、、、、、、。其中部分工具在相同路径下有独立编写的旧版REST端点,响应格式或参数名称不同(接受而非)。请勿假设REST端点与同名工具一致。
list_funnelsget_funnellist_pagesget_pagelist_productsdeliver_orderget_statsGET /productsqsearch一个路径陷阱:列出的是邮件模板(用于设置),而非Puck页面模板。页面模板位于。
/api/v1.1/templates/api/v1.1/page-templatesHonest operational cost
真实运维成本
Say this out loud rather than letting the user discover it after launch:
- Workers path: no servers to patch, but you own the Postgres and its backups, and free-plan limits are daily caps that fail operations rather than billing you. Know which limit you are closest to before a traffic spike.
- Docker path: upgrades, backups and uptime are yours. Schema changes ship with the image and must be applied on upgrade.
- Payment configuration and its PCI scope are the operator's responsibility on every path.
- There is no support SLA on the self-hosted build. Issues and Discussions on GitHub are the channel.
- Budget hours, not minutes, for the first production deployment. The two-minute number is the local Docker evaluation, not a launch.
Documentation: https://autonnel.com/docs · Issues and Discussions: https://github.com/autonnel/autonnel
请明确告知用户,而非让他们上线后才发现:
- Workers路径:无需补丁服务器,但您需负责Postgres及其备份,且免费计划的限额是每日上限,会导致操作失败而非计费。流量高峰前请了解您最接近哪个限额。
- Docker路径:升级、备份和可用性均由您负责。schema变更随镜像发布,升级时必须应用。
- 无论选择哪种路径,支付配置及其PCI合规范围均由运营者负责。
- 自托管版本无服务级别协议(SLA)支持。问题和讨论请通过GitHub渠道提交。
- 首次生产部署请按小时规划时间,而非分钟。两分钟是本地Docker评估的时间,而非上线时间。