Publishing funnel pages with the API

Save page content through the existing Pages API and keep funnel payment mode separate.

The Pages API saves supported content as live content when you create or update a page. There is currently no separate public publish command or status to poll for a page or an entire funnel. A funnel's live_mode controls test versus live payment processing; changing it does not make pages visible.

Save and read back one page

Use Fetch Page to inspect a page and Update Page to replace content intentionally. Both a numeric id and that page's opaque public_id work in the path. The update body has a page root; PUT and PATCH use the existing update operation.

GET /api/v2/pages/63
Authorization: Bearer <access_token>

For a new internal page or an existing page whose owner explicitly approved a full content replacement:

PUT /api/v2/pages/63
Authorization: Bearer <access_token>
Content-Type: application/json

{"page":{"markup":"<section><row cols=\"1\"><column><headline>Hi</headline></column></row></section>"}}

Read the page again after the write. The 200 response is the normal unwrapped Page resource, including numeric id, string public_id, and computed url. Use expand[]=markup only if you need a PML representation; that representation can omit elements the visual editor supports. Never send a round-tripped PML read back solely to publish an existing editor page. The write replaces live content; it is not a saved-draft promotion and does not promise deletion of an older draft blob.

The content path depends on hosting:

  • Internal pages: markup replaces the live visual tree, which the editor reads first when present.
  • Custom HTML pages: custom_html replaces the ClickFunnels-hosted HTML body. Read it through the existing custom HTML endpoint.
  • External SDK pages: deploy the body on your own host. external_url updates the ClickFunnels registration, not that body.

Writes request cache invalidation. A successful response or computed URL does not prove that caches have propagated or that the page is publicly reachable; check the URL separately when delivery matters. Each page is currently written separately, with no atomic release of all funnel pages.

Keep payment mode separate

Fetch Funnel returns the current live_mode. Use Update Funnel only when you intend to change payment processing. false keeps test mode; true enables live payments.

PUT /api/v2/funnels/5
Authorization: Bearer <access_token>
Content-Type: application/json

{"funnel":{"live_mode":false}}

The path accepts numeric or public IDs, and the body uses the funnel root. PUT and PATCH support booleans and the strings "true" and "false"; null, empty, and other values leave the mode unchanged. Read the Funnel back to confirm the value. Its unwrapped response reports payment mode, not a publish status. Use the existing funnel structure endpoint for the step tree rather than constructing page URLs from path fragments.

Access and errors

These operations keep their existing workspace and record permissions, active subscription check, and token scopes. A restricted token needs funnels read scope to fetch and funnels write scope to update, plus its workspace grant. Malformed JSON, a missing required request root, or invalid PML returns 400; wrong page-type fields or validation failures return 422; missing or inaccessible records return 404; invalid credentials return 401; and denied scopes, grants, or subscription access return 403. Errors keep the existing English error and nullable hint fields.

For the MCP connector, call describe_category("funnels") and use fetch or update on page, custom_html_page, external_page, or funnel as appropriate. Supply a granted workspace_id and record id, with flat attributes for updates; the connector supplies the HTTP request root.