my-funnel-api

$npx mdskill add myapihq/myapi/my-funnel-api

Publish raw HTML websites instantly to the edge under any slug.

  • Create and manage websites (funnels) tied to an org.
  • Depends on mydomainapi for custom domain assignment.
  • Overwrites existing content at target slug with no undo.
  • Serves pages from edge within seconds via funnel push.

SKILL.md

.github/skills/my-funnel-apiView on GitHub ↗
---
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
<!-- llm:start -->
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>`.
<!-- llm:end -->

## Commands
<!-- generated:start -->
| 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`. `--json` prints `{slug, subdomain_url, overwritten, org_id, funnel_id}` |
| `myapi funnel publish <dir>` | Upload a whole directory as the funnel's site (`--env dev\|prod`, default prod; `--api-fn <id>`; `--json`). Prod refuses to replace a live site without `--force` |
| `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 |
<!-- generated:end -->

## 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:

1. **Confirm the org.** `--org` (or `default_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 list` shows the orgs you can reach.
2. **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.
3. **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.
4. **Pin the funnel.** When an org has exactly one funnel, `push`/`publish` auto-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.

## Examples
<!-- llm:start -->
```bash
# 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; pass `--funnel` to be sure. `push --json` returns the live URL as `subdomain_url` — no follow-up `funnel get` needed.
<!-- llm:end -->

## 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**):

```bash
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):

```bash
# 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>` and `myapi 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`/`--funnel` explicitly instead of relying on whatever default was set last.
- `--force` means "yes, replace the live page/site" — confirm the `(org, funnel, slug)` target first; don't use it to silence the overwrite error.
- Deleting a funnel purges all its edge pages immediately.
- `402 INSUFFICIENT_FUNDS` → top up (`myapi billing topup`) or enable `myapi billing auto-recharge`.

Run `myapi funnel --help` or `myapi funnel <subcommand> --help` for full flag reference.

More from myapihq/myapi