# Signal configuration & sessions

**Write tools (mutate state).** Signal page rules, form groups, attribution models, Conversions-API destination config, and session recordings/analysis.

:::warning{title="Write tool — mutates state"}

New tokens are read-only by default: the console defaults a new endpoint to the read-only tools, so a fresh token cannot call these until someone deliberately grants a write tool. See [Tool scoping](/tool-scoping) and [Write tools are human-in-the-loop](/tools/overview#write-tools-are-human-in-the-loop).

:::

| Tool | Purpose |
|---|---|
| [`signal_page_rule_upsert`](#signal_page_rule_upsert) | Create or update a conversion page rule |
| [`signal_page_rule_delete`](#signal_page_rule_delete) | Delete a conversion page rule |
| [`signal_form_group_upsert`](#signal_form_group_upsert) | Create or update a form group |
| [`signal_attribution_model_upsert`](#signal_attribution_model_upsert) | Create or update an attribution model |
| [`signal_destination_update_config`](#signal_destination_update_config) | Update a conversions destination's config |
| [`signal_session_delete`](#signal_session_delete) | Delete Signal session recording |
| [`signal_session_enqueue_analysis`](#signal_session_enqueue_analysis) | Enqueue Signal session analysis |

## `signal_page_rule_upsert`

**Create or update a conversion page rule**

Create a page rule, or update an existing one. A matching pageview records a synthetic form submission named by the rule, so it feeds conversion counts, attribution and any Conversions-API destination — write patterns narrowly. Rules are evaluated on every pageview, so only three literal match types exist (exact / prefix / contains) and there is no regex.

**Posture:** mutates state · **Module gate:** none (needs only the agent entitlement) · **REST:** `POST /api/v1/tools/signal_page_rule_upsert`

| Argument | Type | Required | Notes |
|---|---|---|---|
| `id` | string | no | Omit to CREATE a rule; supply it to UPDATE that rule. (pattern `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`) |
| `is_active` | boolean | no | Whether the rule is evaluated on incoming pageviews (defaults to true on create). |
| `match_type` | `exact` \| `prefix` \| `contains` | no | How the pattern is compared: exact and prefix test the URL PATH (so their patterns must start with "/"); contains tests the full URL. There is no regex option. |
| `name` | string | no | The conversion name recorded when the rule matches, e.g. "Quote request". Must be unique per site. (length 1–120) |
| `pattern` | string | no | The path or substring to match, e.g. "/thank-you". Validated against the match type — a pattern-only update is checked against the rule's stored match type. (length 1–500) |
| `site_id` | string | no | Which tracked site the rule belongs to (required when creating). A rule never moves between sites — delete and recreate instead. (pattern `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`) |

## `signal_page_rule_delete`

**Delete a conversion page rule**

Remove a page rule so its pattern stops counting as a conversion. Historical conversions already recorded by the rule are NOT deleted — only future pageviews stop matching.

**Posture:** mutates state · **Module gate:** none (needs only the agent entitlement) · **REST:** `POST /api/v1/tools/signal_page_rule_delete`

| Argument | Type | Required | Notes |
|---|---|---|---|
| `id` | string | **yes** | The page rule to delete. (pattern `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`) |

## `signal_form_group_upsert`

**Create or update a form group**

Group the step form names of one multi-step form under a single name, so conversion rules and send-deduplication treat them as one form rather than one conversion per step. Supplying form_names on an update REPLACES the whole list.

**Posture:** mutates state · **Module gate:** none (needs only the agent entitlement) · **REST:** `POST /api/v1/tools/signal_form_group_upsert`

| Argument | Type | Required | Notes |
|---|---|---|---|
| `form_names` | array of string | no | The observed form names that are steps of ONE form, e.g. ["aq-step1","aq-step2"]. Blanks are dropped and duplicates de-duped; 1–50 unique entries survive. |
| `id` | string | no | Omit to CREATE a group; supply it to UPDATE that group. (pattern `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`) |
| `name` | string | no | Group name, unique in the organization, e.g. "Quote wizard". (length 1–80) |

## `signal_attribution_model_upsert`

**Create or update an attribution model**

Create an attribution model, or update one in place. Models are computed ON READ, so changing one re-cuts how credit is reported across channels immediately and retroactively — say which model you changed when you report results. name and model_type are required on both create and update (an update replaces the model's whole definition).

**Posture:** mutates state · **Module gate:** none (needs only the agent entitlement) · **REST:** `POST /api/v1/tools/signal_attribution_model_upsert`

| Argument | Type | Required | Notes |
|---|---|---|---|
| `model_type` | `first_touch` \| `last_touch` \| `linear` \| `time_decay` \| `position_based` | **yes** | How credit is split across a contact's touchpoints. |
| `name` | string | **yes** | Model name shown in the Signal attribution views. (length 1–120) |
| `config` | object | no | Model-specific settings, e.g. { half_life_days: 7 } for time_decay or { first: 0.4, last: 0.4 } for position_based. Unknown keys are stored as-is. |
| `id` | string | no | Omit to CREATE a model; supply it to UPDATE that model. (pattern `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`) |
| `is_active` | boolean | no | Whether the model runs in the standard attribution computation (default true). |
| `is_default` | boolean | no | Whether this model is the organization's default view (default false). |
| `lookback_days` | integer | no | How far before a conversion touchpoints still earn credit (1–730, default 90). (1–730) |

## `signal_destination_update_config`

**Update a conversions destination's config**

Adjust an EXISTING Conversions-API destination: its name, event map, lookback window, de-duplication window, and whether it is sending. Pausing (is_enabled false) stops outbound conversion sends immediately; resuming also clears the failure counters. Credentials, platform config and the destination's platform cannot be changed here, and destinations cannot be created or deleted through this API.

**Posture:** mutates state · **Module gate:** none (needs only the agent entitlement) · **REST:** `POST /api/v1/tools/signal_destination_update_config`

| Argument | Type | Required | Notes |
|---|---|---|---|
| `destination_id` | string | **yes** | The existing Conversions-API destination to reconfigure. (pattern `^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`) |
| `dedupe_window_hours` | integer | no | At most one send per (rule, person) within this many hours; 0 disables de-duplication. (0–720) |
| `event_map` | object | no | Which platform event each Bellaso event type sends as, e.g. { form_submit: "Lead" }. Replaces the whole map. |
| `is_enabled` | boolean | no | Resume (true → status active, which also clears the failure counters) or pause (false → status paused) sending. |
| `lookback_days` | integer | no | How many days back conversions are eligible to send (1–90). (1–90) |
| `name` | string | no | Display name for the destination. (length 1–80) |

## `signal_session_delete`

**Delete Signal session recording**

Soft-delete a Signal session recording immediately (denies further playback). Object cleanup is asynchronous.

**Posture:** mutates state · **Module gate:** none (needs only the agent entitlement) · **REST:** `POST /api/v1/tools/signal_session_delete`

| Argument | Type | Required | Notes |
|---|---|---|---|
| `session_id` | string | **yes** | (pattern `^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}\|00000000-0000-0000-0000-000000000000\|ffffffff-ffff-ffff-ffff-ffffffffffff)$`) |

## `signal_session_enqueue_analysis`

**Enqueue Signal session analysis**

Enqueue a budgeted LLM analysis job for a session. Idempotent on (session_id, input_hash, model_version, prompt_version). Honors signal_replay_settings analysis_enabled and monthly USD budget. Does not run the model — only enqueues.

**Posture:** mutates state · **Module gate:** none (needs only the agent entitlement) · **REST:** `POST /api/v1/tools/signal_session_enqueue_analysis`

| Argument | Type | Required | Notes |
|---|---|---|---|
| `session_id` | string | **yes** | (pattern `^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}\|00000000-0000-0000-0000-000000000000\|ffffffff-ffff-ffff-ffff-ffffffffffff)$`) |
| `model_version` | string | no | (length 1–128) |
| `prompt_version` | string | no | (length 1–128) |
