---
title: "Replace a funnel"
method: PUT
path: "/sites/{id}/funnels/{funnelId}"
tags: ["Sites"]
---

# Replace a funnel

`PUT /sites/{id}/funnels/{funnelId}`

## Request

- Base URL: `https://statable.com/api/v1`
- URL: `https://statable.com/api/v1/sites/{id}/funnels/{funnelId}`
- Auth: HTTP bearer
- TypeScript: <https://skmtc.dev/statable/apis/statable-stats-api/docs/sites/:id/funnels/:funnelId/put.ts> (a function with typed inputs; its response is checked against the schema)

## Request body

- FunnelRequest
  - `name` string, required
  - `steps` FunnelStep[], required
    - `kind` 'page' | 'event' | 'goal' | 'scroll' | 'entry_page' | 'exit_page', required
    - `path` string: URL path — for kind page/entry_page/exit_page.
    - `operator` string: Path match operator (e|b|c|r) — for kind page/entry_page/exit_page. `r` is an RE2 regex; one that does not compile is refused with 400.
    - `event` string: Custom event name — for kind event.
    - `prop_key` string: Optional custom-property key — for kind event.
    - `prop_value` string: Optional custom-property value — for kind event.
    - `goal_id` integer: Goal id — for kind goal.
    - `threshold` integer: Scroll depth 0..100 — for kind scroll.
  - `scope` 'visitor' | 'session'
  - `strict_order` boolean

## Response `200`

The updated funnel.

- FunnelDefinition: A saved funnel definition (managed in the dashboard).
  - `id` integer
  - `site_id` integer
  - `name` string
  - `scope` 'visitor' | 'session'
  - `strict_order` boolean: When true, steps must occur in exact order (windowFunnel strict_order).
  - `steps` FunnelStep[]
    - `kind` 'page' | 'event' | 'goal' | 'scroll' | 'entry_page' | 'exit_page', required
    - `path` string: URL path — for kind page/entry_page/exit_page.
    - `operator` string: Path match operator (e|b|c|r) — for kind page/entry_page/exit_page. `r` is an RE2 regex; one that does not compile is refused with 400.
    - `event` string: Custom event name — for kind event.
    - `prop_key` string: Optional custom-property key — for kind event.
    - `prop_value` string: Optional custom-property value — for kind event.
    - `goal_id` integer: Goal id — for kind goal.
    - `threshold` integer: Scroll depth 0..100 — for kind scroll.
  - `created_at` string, date-time
  - `updated_at` string, date-time

## Other responses

- `400`: `invalid_request` — the body or a field is not acceptable.
- `401`: Missing/malformed/invalid/revoked bearer token (`unauthorized`), or a key past its expiry (`key_expired`; the message names the expiry time).
- `403`: `insufficient_scope`, `key_not_scoped`, or `not_site_owner`.
- `404`: `write_disabled`, `unknown_site`, or `unknown_funnel`.
- `409`: `funnel_exists`.
- `429`: Hourly account (default 2000/h) or per-key (default 600/h) limit hit (`rate_limited`). Retry after the `Retry-After` seconds. The X-RateLimit-* headers report the window that tripped (account on an account limit).
- `500`: Unexpected server error (`internal`). Report it with the `request_id` from the body or the X-Request-ID header: it is what lets the exact log entry be found, and without it a 500 can only be matched by guessing at a time window.

---

[API](https://skmtc.dev/statable/apis/statable-stats-api.md) - [All operations](https://skmtc.dev/statable/apis/statable-stats-api/llms.txt) - [OpenAPI document](https://skmtc.dev/statable/apis/statable-stats-api/revisions/352b6d47c186?raw)
