name: my-funnel-api version: 1.0.0 description: > Create and publish websites (funnels) to the edge. Push raw HTML to any slug and it goes live instantly on your org's domain or preview subdomain. triggers: [funnel, landing page, website, page, publish, push, slug, html, edge, preview subdomain, makeautonomous] checksum: sha256-pending
MyFunnelAPI
A funnel is a website tied to an org. Push raw HTML pages to slugs and they're served from the edge immediately — no build pipeline, no deploy queue.
Capabilities
Funnels are the publishing surface. You create a funnel under an org (one command), then funnel push raw HTML to any slug (/, /about, /pricing, etc.). The edge serves the page within seconds — no CI/CD, no build, no deploy queue.
Before you push, know where you're writing. funnel push and funnel publish --env prod overwrite whatever is live at the target — no undo. An org may already host a real site; pushing / onto it replaces the homepage. See Namespace & safety below — this is the #1 way agents wreck an existing site.
By default, your funnel lives on a free preview subdomain (*.makeautonomous.com) you get with every org. To serve on a custom domain, register and assign one via mydomainapi first.
Every funnel auto-provisions a webhook at creation time (org_webhook_id). The funnel exposes two public proxy endpoints your HTML can call directly (no API key needed): a form submit at POST /funnel/funnels/{id}/submit/{slug} that delivers submissions through that webhook (CRM upsert + bound workflows fire automatically), and an analytics/event ingest for pageviews and click tracking. For multi-form funnels you can bind individual slugs to specific destinations with myapi funnel form ... --capture-to webhook:<id>.
Commands
| Command | What it does |
|---|---|
myapi funnel create |
Create a funnel in the default org |
myapi funnel list |
List all funnels with preview/domain URLs |
myapi funnel get <id> |
Inspect a funnel's metadata + preview URL |
myapi funnel delete <id> |
Delete the funnel and purge its edge pages |
myapi funnel push [slug] |
Push HTML from stdin to a slug (default: /). Overwrites an existing page — refused without --force, prints the resolved org + funnel on success |
myapi funnel pages [funnel_id] |
List the pages currently published to a funnel |
myapi funnel form [funnel_id] |
Emit canonical form HTML (and register a binding with --capture-to) |
myapi funnel verify [slug] |
Verify a published page is reachable + check links/webhooks |
Namespace & safety (read before any write)
A write targets a (org, funnel, slug) address. Get all three right before pushing — the CLI will help, but the thinking is yours:
- Confirm the org.
--org(ordefault_org) decides whose namespace you touch. For a demo or a new project, pass--org <id>explicitly every time — don't trust the ambient default.myapi org listshows the orgs you can reach. - Look before you write.
myapi funnel list --org <id>shows the org's funnels;myapi funnel pages --funnel <id>shows what's already published. If a slug is taken by something real, you're about to replace it. - A new demo = a new funnel. Don't reuse an org's existing funnel for an unrelated demo.
myapi funnel create --name <demo> --org <id>gives you a clean namespace and its own preview subdomain. - Pin the funnel. When an org has exactly one funnel,
push/publishauto-pick it — convenient, but it's how a demo lands on the wrong site. Pass--funnel <id>(or set a default) so the target is explicit, not inferred.
The CLI backstops you: push refuses to overwrite an existing slug (and publish --env prod refuses to replace a live site) without --force, and both print the resolved org + funnel on success. --force is the deliberate "yes, replace it" — never reach for it just to clear the error; first check whether the clash means you're aimed at the wrong place.
Examples
# New demo, done safely — explicit org, fresh funnel, confirm, then push
myapi org list # which orgs can I reach?
myapi funnel list --org <org_id> # what already lives here?
myapi funnel create --name acme-demo --org <org_id> # clean namespace for the demo
echo '<h1>Hello</h1>' | myapi funnel push / --funnel <new_funnel_id>
# Push multiple pages to that funnel
cat about.html | myapi funnel push /about --funnel <new_funnel_id>
cat pricing.html | myapi funnel push /pricing --funnel <new_funnel_id>
# Inspect what's published before touching an existing funnel
myapi funnel pages --funnel <funnel_id>
myapi funnel verify /pricing --funnel <funnel_id>
# Deliberately replace a live page (only after confirming it's the right target)
cat new-home.html | myapi funnel push / --funnel <funnel_id> --force
# Clean up
myapi funnel delete <funnel_id> --org <org_id>
Omitting [slug] defaults to /. The funnel id is resolved from --funnel, the saved default funnel, or — only if the org has exactly one funnel — auto-picked (so an unintended push can silently land on an existing site; pass --funnel to be sure). push refuses to overwrite an occupied slug without --force.
Form submissions (canonical recipe)
The funnel submit proxy is the canonical form-capture path. Never hardcode https://api.mywebhookapi.com/webhook/in/<slug> into funnel HTML — that URL leaks into your git history, breaks on rotation, gets scraped, and locks the platform out of future form-quality features (rate-limit, captcha, anti-bot, field validation). Use the proxy instead — same plumbing, hidden URL, automatic CRM ingest on email.
Zero-config form (the happy path most agents want) — still pin the org + funnel so the snippet and the page land in the namespace you mean (see Namespace & safety):
myapi funnel create --name acme-demo --org <org_id>
myapi funnel form --slug join --fields email:required,name --funnel <funnel_id> > snippet.html
# paste snippet.html into your page (or pipe through funnel push):
cat page-with-snippet.html | myapi funnel push / --funnel <funnel_id>
# Submissions land in the funnel's auto-provisioned webhook → CRM upsert on `email` → any bound workflow fires.
funnel form always registers a per-slug binding (idempotent on repeat). Without --capture-to it auto-targets the funnel's org_webhook_id — same destination as the fallback, with server-side honeypot + field validation turned on.
Multi-form funnel (each slug to a different destination):
# Bind /checkout to a specific webhook:
myapi funnel form <funnel_id> --slug checkout \
--fields email:required,plan,phone:tel \
--capture-to webhook:<checkout_webhook_id>
# Bind /survey to a workflow directly:
myapi funnel form <funnel_id> --slug survey \
--fields email:required,score:number \
--capture-to workflow:<survey_workflow_id>
--capture-to registers the per-slug binding via POST /funnel/orgs/.../funnels/{id}/forms. Without it, submissions fall through to the funnel's default webhook.
Analytics
POST /funnel/funnels/{id}/event — public proxy for pageviews, clicks, and pixel events (no API key needed). Rate-limited to 60 req/min per funnel.
Notes
- Set defaults with
myapi config set-org <id>andmyapi config set-funnel <id>to skip flags on every command — but a stale default is exactly how a push lands on the wrong org/funnel. For demos and one-offs, pass--org/--funnelexplicitly instead of relying on whatever default was set last. push(any slug) andpublish --env prodoverwrite live content and are refused without--forcewhen something already exists at the target.--forcemeans "yes, replace the live page/site" — confirm you're aimed at the right(org, funnel, slug)before using it, don't use it to silence the error.- Deleting a funnel purges all its edge pages immediately.
402errors mean insufficient credits — runmyapi billing topup <amount>.
Run myapi funnel --help or myapi funnel <subcommand> --help for full flag reference.